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\n",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\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/lalalatianlalu/p/10367432.html