Codeforces Round #480 (Div. 2)

A题:Links and Pearls

只要-的数量能整除o的数量就可,注意特判0

没啥好写的

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 #include <bitset>
 7 typedef long long ll;
 8 using namespace std;
 9 char s[110];
10 int len0=0,len1=0,len=0;
11 int main(){
12     scanf("%s",s+1);
13     len=strlen(s+1);
14     for(int i=1;i<=len;i++){
15         if(s[i]=='-') len0++;
16         else len1++;
17     }
18     if(len0==0) printf("YES
");
19     else{
20         if(len1==0){printf("YES
");return  0;}
21         if(len0%len1==0){printf("YES
");}
22         else printf("NO
");
23     }
24     return 0;
25 }
View Code

B题:Marlin

这也是一个简单构造题

只要围绕x轴对称,或者围绕着y轴对称即可

——————————————这样就很容易想了,如果是偶数的话我们只要从左往右依次上下填满就ok了,这样就可以填偶数的————————————————

——————————————由于中间这个是奇数的,我们只需要把第二排中间先填上,然后按照奇数对称即可———————————————————————

下面是代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 typedef long long ll;
 7 using namespace std;
 8 int n,k;
 9 char s[8][120];
10 int main(){
11     scanf("%d%d",&n,&k);
12     printf("YES
");
13     for(int i=1;i<=4;i++)
14         for(int j=1;j<=n;j++)
15             s[i][j]='.';
16     if(k%2==0){
17         for(int j=2;j<=n-1;j++){
18             for(int i=2;i<=3;i++){
19                 if(k>0){
20                     k--;
21                     s[i][j]='#';
22                 }
23             }
24         }
25     }else{
26         k--;s[2][(n/2)+1]='#';
27         int q=(n-3)/2,t=(n/2)+1;
28         //cout<<q<<endl;
29         for(int i=2;i<=3;i++){
30             for(int j=1;j<=q;j++){
31                 if(k>0){
32                     k--;k--;
33                     s[i][t-j]='#';
34                     s[i][t+j]='#';
35                 }
36             }
37         }
38     }
39     for(int i=1;i<=4;i++){
40         for(int j=1;j<=n;j++) printf("%c",s[i][j]);
41         printf("
");
42     }
43     return 0;
44 }
View Code

————————————————————————————————————————————

这个n是奇数其实是关键所在,是应该一下子就要反应过来的!

其他按照对称性就ok

这个n是奇数的作用就是保证奇数次能有位置放

————————————————————————————————————————————

这道题怎样搞都可以,主要是发现一下这个的对称性!!!!!!!!!!!

当时思考这道题是脑子是乱的,连简单的对称性都看不出

其实还有一个原因是我对这个图形一点都不敏感,这个才是问题的关键!!!!!!!!!!!

————————————————————————————————————————————

C题:Posterized

————————————————————————————————————————————

这个题就更简单了,我感觉思维就很明确的那种,就是贪心,直接往前面找,然后复杂度是o(n*255)

一开始还读错了题,看来读题是真的很重要重要

下面是代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 typedef long long ll;
 7 using namespace std;
 8 const int maxn=(int)(1e5+1000);
 9 int n,k;
10 int num[maxn];
11 int vis[270];
12 int las[maxn];
13 int main(){
14     scanf("%d%d",&n,&k);
15     for(int i=1;i<=n;i++) scanf("%d",&num[i]);
16     for(int i=1;i<=n;i++){
17         if(vis[num[i]]!=0){
18             for(int j=num[i];j>=max(num[i]-k+1,0);j--){
19                 if(vis[j]!=vis[num[i]]) break;
20                 las[i]=j;
21             }
22         }else{
23             int flag=-1;
24             for(int j=num[i];j>=max(num[i]-k+1,0);j--){
25                 if(vis[j]==0) continue;
26                 flag=j;las[i]=j;break;
27             }
28             if(flag==-1){
29                 las[i]=max(num[i]-k+1,0);
30                 for(int j=num[i];j>=max(num[i]-k+1,0);j--) vis[j]=i;
31                 continue;
32             }
33             for(int j=las[i];j>=0;j--){
34                 if(vis[j]==vis[las[i]]){flag=j;}
35                 else break;
36             }
37             if((num[i]-flag+1)<=k){
38                 las[i]=flag;
39                 for(int j=flag;j<=num[i];j++) vis[j]=vis[flag];
40                 continue;
41             }else{
42                 for(int j=las[i]+1;j<=num[i];j++) vis[j]=i;
43                 las[i]=las[i]+1; continue;
44             }
45         }
46     }
47     for(int i=1;i<=n;i++){
48         if(i==n) printf("%d
",las[i]);
49         else printf("%d ",las[i]);
50     }
51     return 0;
52 }
View Code

________________________________________________________________________________________

D题:Perfect Groups

这个题目主要是题意难度,感觉读懂以后还是挺好做的

主要是传递性的问题,要能保证接下来能传递下去,只要搞好了这一点就不难了。

这个我们假设能分一组的是什么样的情况,就是假设 a*b是一个平方数,b*c是一个平方数。那么

a*c也是一个平方数

这个还是挺好证明的。就是a的奇数次的因子的位置和b的奇数次的因子的位置刚好对上,b的奇数次

因子的个数和c的奇数次因子的个数刚好对上。。。。。。。。。。。。

这样对上以后我们就可以我们利用传递性来做了

这样预处理一下,确定a[j]最前面的那个可以和它组合的因子是那个。

还有确定0的话可以放在任何一组,不要管他,0直接跳过即可。

然后预处理一下,再枚举一下就ok了

下面是代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 #include <bitset>
 7 typedef long long ll;
 8 using namespace std;
 9 const int maxn=(int)(5e3+100);
10 int n;
11 ll num[maxn],pre[maxn],ans[maxn];
12 int main(){
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
15     for(int i=1;i<=n;i++){
16         if(num[i]==0) continue;
17         for(int j=i-1;j>=1;j--){
18             if(num[j]==0) continue;
19             if((num[j]*num[i])<0) continue;
20             ll d=num[j]*num[i];
21             ll q=(ll)sqrt(d);
22             if(d==(ll)(q*q)){
23                 pre[i]=j;break;
24             }
25         }
26     }
27 
28     for(int i=1;i<=n;i++){
29         int snum=0;
30         for(int j=i;j<=n;j++){
31             if(pre[j]<i&&num[j]!=0) snum++;
32             ans[max(snum,1)]++;
33         }
34     }
35 
36     for(int i=1;i<=n;i++){
37         if(i==n) printf("%lld
",ans[i]);
38         else printf("%lld ",ans[i]);
39     }
40     return 0;
41 }
View Code

E题:The Number Games

首先我们应该知道一点,就是有  2^(n+1)>2^n+2^(n-1)+....+2^1=2^(n+1)-2

所以我们可以知道一点是我们应该是尽量保存大点,丢掉小的。

所以有一种想法是直接按照度丢掉小的,但是这样是错误的。直接画个图就可知道。

然后我觉得有一个肯定没有错的想法是保留大,即保留前n-k个大的。

这个怎么保留呢,那么肯定一点是要以n为根把n留下来。

接下来的想法是把n-1留下来,那么n-1这条链也要保存下来,那么n-1的这条链怎么保存呢????

这个要验证,这个验证的话不能用暴力,得用倍增确定这个点要不要保存,就是往上面调一下就可以

这个可以做到logn单步验证。

下面是代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cmath>
 6 #include <bitset>
 7 #include <vector>
 8 #include <queue>
 9 typedef long long ll;
10 using namespace std;
11 const int maxn=(int)(1e6+100);
12 int n,k;
13 int ans[maxn];
14 int tot=0;
15 int in[maxn];
16 vector<int> G[maxn];
17 priority_queue<int> que;
18 int main(){
19     scanf("%d%d",&n,&k);
20     for(int i=1;i<n;i++){
21         int u,v;
22         scanf("%d%d",&u,&v);
23         in[u]++;in[v]++;
24         G[u].push_back(v);
25         G[v].push_back(u);
26     }
27     for(int i=1;i<=n;i++){
28         if(in[i]==1) que.push(-i);
29     }
30 
31     while(k){
32         k--;
33         int u=abs(que.top());
34         ans[++tot]=abs(que.top());
35         que.pop();
36         for(int i=0;i<G[u].size();i++){
37             int v=G[u][i];
38             in[v]--;
39             if(in[v]==1){
40                 que.push(-v);
41             }
42         }
43     }
44 
45     sort(ans+1,ans+tot+1);
46     for(int i=1;i<=tot;i++){
47         if(i==tot) printf("%d
",ans[tot]);
48         else printf("%d ",ans[i]);
49     }
50     return 0;
51 }
View Code

——————————————————————————————————————

这个该怎么来想呢?我们应该确定的一些事情是这个确实难搞

  2^(n+1)>2^n+2^(n-1)+....+2^1=2^(n+1)-2   (这个信息是重中之重)

 然后我们变成一点,保存大的,这个是肯定没错的(直接按度数丢掉小的是错误的,刚才证明了,

这个其实有点难搞,因为需要证明)(以后最好就直接往直接正确上面的逻辑上面去想)

保存大的之后,我们很好引入思维了,就是以n为根,接下来一个个贪心的保存,这个如果

保存了i,i到根上面的数都要保存,这个也比较好搞,用个树上倍增即可,好搞的很

——————————————————————————————————————

原文地址:https://www.cnblogs.com/pandaking/p/12132355.html