• 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;
    }
  • 相关阅读:
    ruby -- 修改rubymine的字体大小
    ruby -- 基础学习(二) 外键配置实现级联删除
    ruby -- 基础学习(一)项目文件夹说明
    ruby -- 问题解决(二)rails4.0create引起的ActiveModel::ForbiddenAttributesError错误
    ruby -- 问题解决(一)无法连接mysql数据库
    enumerate用法
    python文件调用
    第二天----列表、深浅拷贝、元组、字符串、算数运算、字典、while
    P1005 矩阵取数游戏(动态规划+高精度)
    P1242 新汉诺塔(搜索+模拟退火)
  • 原文地址:https://www.cnblogs.com/liyongqi/p/13040838.html
Copyright © 2020-2023  润新知