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;
}
原文地址:https://www.cnblogs.com/liyongqi/p/13040838.html