2020.06.01——习题训练4
A - Dreamoon and Ranking Collection
题意:
给定n个数,代表他获得的排名,然后再给定x,问进行x场比赛后,能得到1到某个范围内的所有排名。
题解:
大概可以算是桶排吧,每得到一个排名就对它的数组++,然后再一个从1开始的遍历,如果这个数的数组还是0就对他++,然后x就--,直到x为0后看数组遍历到了哪。
代码:
#include<bits/stdc++.h> using namespace std; int main(){ int t; cin>>t; while(t--){ int n,x,l=1; int a[300],b[500]; memset(b,0,sizeof(b)); cin>>n>>x; for(int i=1;i<=n;i++){ cin>>a[i]; b[a[i]]++; } for(int i=1;i<=x;i++){ if(b[l]!=0){ l++; i--; } else{ b[l]++; l++; } } for(int i=1;i<=300;i++){ if(b[i]==0){ cout<<i-1<<endl; break; } } } return 0; }
B - Dreamoon Likes Permutations
题意:
给定l1和l2,2个序列,然后把它们加在一起,问合在一起的序列可以拆成不同的l1,l2的个数。(l1,l2是一个从1到它的最大值都存在的序列)
题解:
一开始想用sum把它们加起来判断,然后样例是过了,但是又有特殊情况不能判断(1 2 4 3 3 1 3,如果这样前面4个的和也等于后面4个的和但是是不成立的),然后就换了一个思路,其实只要用sort对1到maxn 和maxn+1到n进行排序然后判断,和1到n-maxn和n-maxn+1-n进行判断,再特判一下n/2=maxn的情况因为如果左边成立且右边成立就是算一种(1 2 3 1 2 3,这样应该输出 1 3 3)。
代码:
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(false); int t,n,flag1,flag2; int maxn; cin>>t; while(t--){ int flag1=1,flag2=1,maxn=-1; cin>>n; int a[n+10],b[n+10]; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=0;i<n;i++){ cin>>a[i]; b[i]=a[i]; maxn=max(maxn,a[i]); } sort(a,a+maxn);//第一个序列 sort(a+maxn,a+n);//第二个序列 for(int i=0;i<maxn;i++){ if(a[i]!=i+1){ flag1=0; break; } } for(int i=maxn;i<n;i++){ if(a[i]!=i-maxn+1){ flag1=0; break; } } sort(b,b+n-maxn); sort(b+n-maxn,b+n); for(int i=0;i<n-maxn;i++){ if(b[i]!=i+1){ flag2=0; break; } } for(int i=n-maxn;i<n;i++){ if(b[i]!=i-n+maxn+1){ flag2=0; break; } } //cout<<flag1<<" "<<flag2<<endl; if((flag1==1||flag2==1)&&maxn==n/2){ cout<<1<<endl; cout<<maxn<<" "<<n-maxn<<endl; continue; } if(flag1==0&&flag2==0){ cout<<0<<endl; } if(flag1==1&&flag2==0){ cout<<1<<endl; cout<<maxn<<" "<<n-maxn<<endl; } if(flag2==1&&flag1==0){ cout<<1<<endl; cout<<n-maxn<<" "<<maxn<<endl; } if(flag1==1&&flag2==1){ cout<<2<<endl; cout<<maxn<<" "<<n-maxn<<endl; cout<<n-maxn<<" "<<maxn<<endl; } } return 0; }
C - Exercising Walk
题意:
给定一个范围,再给定向左,右,上,下移动的个数,问是否会超出范围。
题解:
以为只要判断最终到达的点是否超出范围就好,其实还要再判断一个就是如果给的范围是一条竖线,就不能向左和向右,如果是一条横线就不能向上和向下。
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; int main(){ int t; cin>>t; while(t--){ ll a,b,c,d;//左 右 下 上 ll x,y,x1,y1,x2,y2; ll sum1,sum2; int flag=0; cin>>a>>b>>c>>d; cin>>x>>y>>x1>>y1>>x2>>y2; sum1=a-b;// sum2=c-d; //cout<<sum1<<" "<<sum2<<endl; x-=sum1; y-=sum2; if(x1==x2){ if(a!=0||b!=0){ flag--; } } if(y1==y2){ if(c!=0||d!=0){ flag--; } } if(x>=x1&&x<=x2){ flag++; } if(y>=y1&&y<=y2){ flag++; } if(flag==2){ cout<<"Yes"<<endl; } else{ cout<<"No"<<endl; } } return 0; }
D - Composite Coloring
题意:
就是给了好多的合数,然后要求把他们填满颜色,在1000个数里只要11个颜色就可以填满,然后给定一个序列,问几个颜色可以填满,如何填。
题解:
一开始我就以为枚举暴力,只要gcd(a[i],a[j])!=1就对这个数填上color,color++.然后样例都没过,根据大佬的说法就是根据最小的素数进行涂色(合数能由多个质数的相乘得到,例如 4 = 2·2,14 = 2·7,63 = 3·3·7等等),因为范围是1000,而第11个素数是31,第12个素数大于1000,所以不会超过11个颜色,那就直接打个表把11个素数记录下来,然后枚举判断如果这个数%prime(i)==0就对它涂上颜色就可以了,如果相同的最小素数就涂上相同的颜色。
代码:
#include<bits/stdc++.h> using namespace std; int prime[11]={2,3,5,7,11,13,17,19,23,29,31}; int main(){ int t; cin>>t; while(t--){ int n; int color=0; cin>>n; int a[3001]; int b[3001]; int ans[3001]; memset(b,0,sizeof(b)); memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ for(int j=0;j<11;j++){ if(a[i]%prime[j]==0){ if(b[prime[j]]==0){//判断这个素数是否染上颜色 b[prime[j]]=++color; } ans[i]=b[prime[j]]; break; } } } cout<<color<<endl; for(int i=1;i<=n;i++){ cout<<ans[i]<<" "; } cout<<endl; } return 0; }
E - K-th Beautiful String
题意:
按字典顺序排序,问n个英文时,第k个字符串是什么样的。
题解:
根据给定的10个字符串,其实是有规律的,前面一个b的顺序是根据 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5来的,所以就是从l=1开始减每减一次l++,看前面的b在哪一个位置上,减到k<=0时,l是多大前面的b就在n-l+1上。而后面的b也是根据前面的b来判断的,当循环后得到的k的绝对值是多少就是前面的b后面的第几位。比如 (5 6,就是从while(k>0){k-=l; l++;}得到l=4然后n-l+1=2表示在第二位,而得到的k是0也就是说下一个b在前面一个b刚好下一格上)
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; int main(){ int t; cin>>t; while(t--){ ll n,k,l=1,d; int flag; cin>>n>>k; while(k>0){ k-=l; d=abs(k); l++; } //cout<<n-l+1<<endl; //cout<<d<<endl; for(int i=1;i<=n;i++){ if(i==n-l+1){ cout<<"b"; flag=i; break; } else{ cout<<"a"; } } for(int i=flag+1;i<=n;i++){ if(i==flag+1+d){ cout<<"b"; } else{ cout<<"a"; } } cout<<endl; } return 0; }
F - Carousel
题意:
把围成一圈的旋转木马涂色,如果类型不同相邻的木马涂上不同的颜色,问最少可以涂多少。
题解:
根据木马的个数判断,如果它们只有一个颜色那就输出1,如果n是奇数
那么我们希望最后一个数c[n]两边的颜色c[1]和c[n - 1]尽可能相同,这样我们就不用使用第三种颜色,使答案最佳
如果c[1] != c[n - 1]且c[n]与相邻两个数c[1]和c[n - 1]都不相同,那么c[n] = 2(最后答案会加1),否则t[n] == t[n - 1] ->c[n] = c[n -1]或者 t[n] == t[1] -> c[n] = c[1]
。(参照大佬题解与代码,我也就读明白了。。)
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 2e5 + 10; int t[N], c[N]; int main() { int q; cin >> q; while (q --){ int n; scanf("%d", &n); int num = 0; for (int i = 1; i <= n; ++ i){ scanf("%d", &t[i]); if (t[i] == t[1]) num ++; } if (num == n){ cout << 1 << endl; for (int i = 1; i < n; ++ i) printf("1 "); cout << 1 << endl; continue; } c[1] = 0; for (int i = 2; i <= n - 1; ++ i) c[i] = c[i - 1] ^ 1; if (n & 1){ for (int i = 2; i <= n - 1; ++ i){ if (t[i] == t[i - 1]){ for (int j = i; j <= n - 1; ++ j){ c[j] ^= 1; } break; } } } int ans = 2; if (c[n - 1] == c[1]){ c[n] = c[1] ^ 1; }else { if (t[n] != t[n - 1] && t[n] != t[1]){ ans = 3; c[n] = 2; }else { if (t[n] == t[1]) c[n] = c[1]; else c[n] = c[n - 1]; } } cout << ans << endl; for (int i = 1; i < n; ++ i) printf("%d ", c[i] + 1); cout << c[n] + 1 << endl; } return 0; }