用灰号打的div2但我还是写div1题解吧(因为div2前2题过水)
A
可以发现这样的做法:每次找到最靠后的与b不同从串,然后通过旋转满足条件。但要判断a的第一位与该位是否相同,若相同,则需变换第1位使得其满足翻转后与该位相同,操作数2*n。至于翻转操作,打标记即可
#include<bits/stdc++.h> using namespace std; const int N=2e5+7; int n,k,t,a[N],b[N],c[N]; char sa[N],sb[N]; void solve(int l,int r) { if(l==r){if((a[l]^t)!=b[1])c[++k]=1;return;} int now=r,m=abs(r-l)+1,dir=l<r?-1:1,tmp=m; while(now-dir!=l&&(a[now]^t)==b[tmp])now+=dir,tmp--; if(now-dir==l)return; if(now==l){c[++k]=1;return;} if((a[l]^t)==b[tmp])c[++k]=1,a[l]^=1; t^=1,c[++k]=abs(l-now)+1; solve(now,l-dir); } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%s%s",&n,sa+1,sb+1); k=t=0; for(int i=1;i<=n;i++)a[i]=sa[i]-'0',b[i]=sb[i]-'0'; solve(1,n); printf("%d",k);for(int i=1;i<=k;i++)printf(" %d",c[i]); puts(""); } }
B
从大到小搜索数,若该数未标记,则该数后面所有未标记的数都与该数在一个集合,并将其标记,记录该集合大小。统计完所有集合大小,再进行背包DP
#include<bits/stdc++.h> using namespace std; const int N=4005; int n,m,a[N],p[N],b[N],w[N]; bool f[N]; int main() { int T;scanf("%d",&T); f[0]=1; while(T--) { scanf("%d",&n); for(int i=1;i<=2*n;i++)scanf("%d",&a[i]),p[a[i]]=i,f[i]=0; f[0]=1; for(int i=1;i<=2*n;i++)b[i]=1; m=0; for(int i=2*n;i;i--) if(b[p[i]]) { w[++m]=0; for(int j=p[i];j<=2*n;j++)if(b[j])b[j]=0,++w[m]; } for(int i=1;i<=m;i++) for(int j=n;j>=w[i];j--) f[j]|=f[j-w[i]]; if(f[n])puts("YES");else puts("NO"); } }
div2 rank9 rating+=523(总算找到一点做题感觉)