Codeforces Round #480 (Div. 2)
只要-的数量能整除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\n"); 19 else{ 20 if(len1==0){printf("YES\n");return 0;} 21 if(len0%len1==0){printf("YES\n");} 22 else printf("NO\n"); 23 } 24 return 0; 25 }
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\n"); 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("\n"); 42 } 43 return 0; 44 }
————————————————————————————————————————————
这个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\n",las[i]); 49 else printf("%d ",las[i]); 50 } 51 return 0; 52 }
________________________________________________________________________________________
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\n",ans[i]); 38 else printf("%lld ",ans[i]); 39 } 40 return 0; 41 }
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\n",ans[tot]); 48 else printf("%d ",ans[i]); 49 } 50 return 0; 51 }
——————————————————————————————————————
这个该怎么来想呢?我们应该确定的一些事情是这个确实难搞
2^(n+1)>2^n+2^(n-1)+....+2^1=2^(n+1)-2 (这个信息是重中之重)
然后我们变成一点,保存大的,这个是肯定没错的(直接按度数丢掉小的是错误的,刚才证明了,
这个其实有点难搞,因为需要证明)(以后最好就直接往直接正确上面的逻辑上面去想)
保存大的之后,我们很好引入思维了,就是以n为根,接下来一个个贪心的保存,这个如果
保存了i,i到根上面的数都要保存,这个也比较好搞,用个树上倍增即可,好搞的很
——————————————————————————————————————