• Codeforces Round #201 (Div. 2) 题解


    A.Difference Row

      题意:给你n个数,让你重新排列,使的每个数减去后面的数的加和最大(最后一个数后面没有数),如果有多组最大值相同,打印字典序最小的情况

      思路:因为所有数的加和中间会相互抵消,最后只剩下第一项减去最后一项,之所以我们要得到最大值就把最大的放在第一个,最小的放在最后一个,中间按照从小到大进行排序就可以

      代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    vector<int> a;
    int ans[105];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            a.push_back(x);
        }
        sort(a.begin(),a.end());
        for(int i=2;i<n;i++){
            ans[i]=a[i-1];
        }
        ans[1]=a[n-1];ans[n]=a[0];
        for(int i=1;i<=n;i++){
            printf("%d ",ans[i]);
        }
        return 0;
    }
    View Code

    B.Fixed Points

      题意:给你n个数,只有一次交换机会,可以交换任意两个数,问你交换后最多有多少数满足a[i]==i

      思路:首先看一下有多少组是满足a[i]==i,因为只有一次交换机会,所以查看剩下不在位置上的数能否交换后满足两个都在位置上,如果没有随便交换一个。

      代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e5+7;
    int a[maxn];
    map<int,int>mp;
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        int ans=0;
        for(int i=0;i<n;i++){
            if(a[i]==i)ans++;
            else{
                mp[a[i]]=i+1;
            }
        }
        map<int,int>::iterator it;
        bool ok=true;
        for(it=mp.begin();it!=mp.end();it++){
            int as=it->first;
            int qw=it->second;
            if(a[as]==qw-1){
                ok=false;
                break;
            }
        }
        if(!ok)ans+=2;
        else ans+=1;
        printf("%d
    ",min(n,ans));
        return 0;
    }
    View Code

    C.Alice and Bob

      题意:集合中有n个数,每次可以选两个数,把他们的差加入到集合中,谁无法加入新的数就输,Alice先手,问最后获胜的是谁

      思路:假设有两个数ab,那么能加入的数就是a-(a-b),这样一直下去最小的就是gcd,所以求出所有数的gcd,这是最小的数,最大的数是数列中最大的数,查看还需要加几个数,判断下奇偶性即可

      代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    int a[105];
    int gcd(int x,int y)
    {
        return y==0?x:gcd(y,x%y);
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        int maxe=-1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            maxe=max(maxe,a[i]);
        }
        int as=a[1];
        for(int i=2;i<=n;i++){
            as=gcd(as,a[i]);
        }
        int ans=maxe/as-n;
        if(ans&1)puts("Alice");
        else puts("Bob");
        return 0;
    }
    View Code

    D.Lucky Common Subsequence

      题意:给你两个字符串ab,以及一个字符串c,求出ab中的LCS使的c不是他们的子串

      思路:定义dp[i][j][k]表示第一个串中的第i位,与第二个串中的第j位,目前匹配了c中的k位,直接三层枚举,第一层为i…lena,第二层为j…lenb,第三层为k…lenc.和LCS相同,如果a[i]==b[j],此时在查看a[i]是否与枚举的c[k]相等,相等就转移,如果a[i]!=c[k],就利用next数组从前面一个字符转移过来。在转移的时候同时维护是从哪里转移过来的,最后打印反推回去即可。

      代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=105;
    int dp[maxn][maxn][maxn];
    int pre[maxn][maxn][maxn][3];
    char a[maxn],b[maxn],c[maxn];
    int Next[maxn];
    char ans[maxn];
    
    void init(int n)
    {
        Next[0]=-1;
        int i=0,j=-1;
        while(i<n){
            if(j==-1||c[i]==c[j]){
                i++;j++;
                Next[i]=j;
            }
            else j=Next[j];
        }
    }
    void solve(int x,int y,int z,int x1,int y1,int z1,int v)
    {
        if(dp[x][y][z]<dp[x1][y1][z1]+v){
            dp[x][y][z]=dp[x1][y1][z1]+v;
            pre[x][y][z][0]=x1;
            pre[x][y][z][1]=y1;
            pre[x][y][z][2]=z1;
        }
    }
    int main()
    {
        scanf("%s%s%s",a+1,b+1,c);
        int lena=strlen(a+1),lenb=strlen(b+1),lenc=strlen(c);
        memset(pre,-1,sizeof(pre));
        memset(dp,0,sizeof(dp));
        init(lenc);
        for(int i=1;i<=lena;i++){
            for(int j=1;j<=lenb;j++){
                for(int k=0;k<lenc;k++){
                    solve(i,j,k,i-1,j,k,0);
                    solve(i,j,k,i,j-1,k,0);
                    if(a[i]==b[j]){
                        if(a[i]==c[k]){
                            solve(i,j,k+1,i-1,j-1,k,1);
                        }
                        else{
                            int p=Next[k];
                            while(p!=-1&&a[i]!=c[p])p=Next[p];
                            if(p==-1)p=0;
                            if(a[i]==c[p])solve(i,j,p+1,i-1,j-1,k,1);
                            else solve(i,j,p,i-1,j-1,k,1);
                        }
                    }
                }
            }
        }
        int pos;
        int maxe=-1;
        for(int i=0;i<lenc;i++){
            if(dp[lena][lenb][i]>maxe){
                maxe=dp[lena][lenb][i];
                pos=i;
            }
        }
        if(maxe==0)puts("0");
        else{
            int res=maxe;
            int x=lena,y=lenb,z=pos;
            while(pre[x][y][z][0]!=-1){
                int xx=pre[x][y][z][0];
                int yy=pre[x][y][z][1];
                int zz=pre[x][y][z][2];
                if(x-xx==1&&y-yy==1&&a[x]==b[y]){
                    ans[res]=a[x];
                    res--;
                }
                x=xx;y=yy;z=zz;
            }
            for(int i=1;i<=maxe;i++){
                printf("%c",ans[i]);
            }
            puts("");
        }
        return 0;
    }
    View Code

    E.Number Transformation II

      题意:给你n个数,以及ab,问你最少几次操作使的a变为b,有两种操作,操作一是使a减1,操作二是使a变为(a-(a%xi))(1<=i<=n)

      思路:每次操作贪心的使a变得更小,因为dp[k]表示减去b+k变为k的最小步数,他是单调的,所以可以贪心的向下减

      代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e5+7;
    set<int>mp;
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            mp.insert(x);
        }
        int a,b;
        scanf("%d%d",&a,&b);
        int ans=0;
        set<int>::iterator it;
        while(a>b){
            int minn=a-1;
            for(it=mp.begin();it!=mp.end();){
                int x=*it;it++;
                if(a-(a%x)<b){
                    mp.erase(x);
                }
                else minn=min(minn,a-(a%x));
            }
            a=minn;
            ans++;
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    洛谷 P1521 求逆序对
    火柴棒等式(2008年NOIP全国联赛提高组)
    扫雷游戏
    数字统计(2010年NOIP全国联赛普及组)
    祖瑪
    巧克力棒&&新年的巧克力棒
    关押罪犯(2010年NOIP全国联赛提高组)
    大整数运算||高精度运算
    國王遊戲(2012年NOIP全国联赛提高组)
    谁拿了最多奖学金(2005提高组第一题)
  • 原文地址:https://www.cnblogs.com/lalalatianlalu/p/10367432.html
Copyright © 2020-2023  润新知