题目给你蓝,红问你哪种大的更多一些?首先我们比较大小肯定会考虑最高位,然后考虑次高位,但是这些又有什么用呢,直接比较蓝红的数量就行了.
#include <bits/stdc++.h> using namespace std; const int N=2e5+500; int w[N]; char s1[N],s2[N]; int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); scanf("%s",s1+1); scanf("%s",s2+1); int num1=0,num2=0; for(int i=1;i<=n;i++) { if(s1[i]>s2[i]) num1++; else if(s1[i]<s2[i]) num2++; } if(num1>num2) puts("RED"); else if(num1==num2) puts("EQUAL"); else puts("BLUE"); } return 0; }
考虑合法的情况,就是按题意说的,每次你选择一次上下,下次只能选择左右,你选择一次左右,那么下次只能选择左右.所以可知上下的数量和左右数量的绝对值不会超过1,所以我们就知道,假如给你次操作,左右的操作和是的,上下的操作和为的,那么我们不妨枚举左的操作次数,和上的操作次数,这样,右的操作次数和下的操作次数就已知了.如此即可解决此问题,我们这里为了简单,用set记录点的数量.
#include <bits/stdc++.h> using namespace std; set<pair<int,int> >ans; int main() { int n;cin>>n; int x=n/2,y=n-x; for(int i=0;i<=x;i++)//上 { for(int j=0;j<=y;j++)//右 { int down=(x-i);int left=(y-j); ans.insert({j-left,i-down}); } }swap(x,y); for(int i=0;i<=x;i++)//上 { for(int j=0;j<=y;j++)//右 { int down=(x-i);int left=(y-j); ans.insert({j-left,i-down}); } }cout<<ans.size()<<endl; return 0; }
考虑gcd的辗转相除法公式有,如此推至n项即是
然后我们每次都是给区间加上一个确定的数,我们可以观察2-n项会发现,他们的gcd是不变的,我们可以求出2-n项的gcd,然后每次改变的值即可求得答案了,注意相减是有负数产生排序一下即可.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+5; ll a[N]; int main() { ll ans=0; ll n,m; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+1+n); for(int i=2;i<=n;i++) ans=__gcd(ans,a[i]-a[i-1]); while(m--) { ll x; scanf("%lld",&x); printf("%lld ",__gcd(ans,a[1]+x)); }puts(""); return 0; }
考虑dp,令表示.到了第i个,选了j个,填了多少容量.一个很显然的想法是拿背包写,没错,就是背包,你拿背包填就完事,最后的价值是不可能超过容量的2倍的,因为我扩大了1倍.也就是不会超过容量的一倍的.
#include <bits/stdc++.h> using namespace std; const int N=105; int a[N],b[N]; int f[N][N][N*N];//到了第i个,选了j个,填了多少容量. int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&a[i],&b[i]); }int sum=0; memset(f,-0x3f,sizeof(f)),f[0][0][0]=0; for(int i=1;i<=n;i++) { sum+=a[i]; for(int j=0;j<=i;j++) { for(int k=0;k<=sum;k++) { if(j&&k>=a[i]) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-a[i]]+2*b[i]); f[i][j][k]=max(f[i][j][k],f[i-1][j][k]+b[i]); } } } for(int i=1;i<=n;i++) { int ans=0; for(int j=0;j<=sum;j++) { ans=max(ans,min(2*j,f[n][i][j])); } printf("%.10f ",(double)ans/(2.0)); }puts(""); return 0; }
这题了解下I,C的操作就挺简单的了.然后就是开个x[]数组记录下偏移值.
#include <bits/stdc++.h> using namespace std; const int N=1005,M=3; int a[N*N][M]; int ans[N][N]; int p[3],x[3];//置换后的id,i,j,k的增值. char s[N*N]; int n,m; void del(int &u) { u--;if(u<0) u+=n; } void add(int &u) { u++;if(u>=n) u-=n; } void solve() { for(int i=0;i<3;i++) x[i]=0,p[i]=i; for(int i=1;i<=m;i++) { if(s[i]=='R') add(x[p[1]]); if(s[i]=='L') del(x[p[1]]); if(s[i]=='D') add(x[p[0]]); if(s[i]=='U') del(x[p[0]]); if(s[i]=='I') swap(p[1],p[2]); if(s[i]=='C') swap(p[0],p[2]); } for(int i=1;i<=n*n;i++) { for(int j=0;j<3;j++) { a[i][j]=(a[i][j]+x[j]-1)%n+1; }ans[a[i][p[0]]][a[i][p[1]]]=a[i][p[2]]; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { printf("%d ",ans[i][j]); }puts(""); } } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&a[(i-1)*n+j][2]); a[(i-1)*n+j][0]=i;a[(i-1)*n+j][1]=j; } scanf("%s",s+1); solve(); } return 0; }
这题你把题目给定的01串转化成图,我们对于表示建图,反之,它给定的操作其实就是告诉你,它是个无向图.然后我们尽量往前走就ok,注意要走完n步.难点在于想到转化.
#include <bits/stdc++.h> using namespace std; const int N=5e5+500; char s[N]; int ep[N];//记录i->i+1有几条边. void solve() { scanf("%s",s+1);int n=strlen(s+1);int id=n; for(int i=1;i<=n;i++)//一共会运行n次. { if(s[i]-'0') ep[id++]++; else ep[--id]++; }id=n; for(int i=1;i<=n;i++) { if(ep[id-1]&&(!ep[id]||ep[id-1]>1)) { ep[--id]--; printf("0"); } else { ep[id++]--; printf("1"); } }puts(""); } int main() { int T; scanf("%d",&T); while(T--) solve(); return 0; }