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; }
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; }
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; }
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; }
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; }