CF1237H. Balanced Reversals
阿新 • • 發佈:2020-11-23
題目大意
給出長為n(n是偶數)的01串S,每次可以把一個長度為偶數的字首翻轉,構造至多n+1次操作把串S變成串T或輸出無解
n<=4000
題解
講雜題時並沒有給出操作次數限制,所以以為可以亂做,想每次翻到末尾,這樣是3/2n次
首先把兩個合成一組,如果01+10、00、11的個數不相等就無解
然後考慮從頭開始構造,維護一段字首[1,i]使得rev(S[1,i])=T[1,i],接著每次用兩次操作即可把後面的某個接到前面來,最後再把[1,n-2]翻轉即可得到T,過程中由於翻了兩次所以01和10不會變
問題是使一開始的01和10個數相等,找到ST中0110差絕對值較大者,將其的一個字首翻轉
因為差的絕對值越大說明01的個數越靠近0或n/2,反過來的過程中一定會與另一個相遇
總操作次數為2(n/2-1)+1+1=n
code
#include <bits/stdc++.h> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b; a>=c; a--) #define abs(x) ((x)>0?(x):-(x)) #define ll long long //#define file using namespace std; int a[4001],b[4001],sum[4],Sum[4],Q,n,N,i,j,k,l,Ls,tot; int ans[4002]; char S[4001],T[4001]; void swap(int &x,int &y) {int z=x;x=y;y=z;} int turn(char a,char b) {if (a==b) {return (a=='0')?2:3;} if (a=='0') return 0;return 1;} void rev(int *a,int t) { int i; fd(i,t/2,1) swap(a[i],a[t-i+1]); fo(i,1,t) if (a[i]<=1) a[i]^=1; } int main() { #ifdef file freopen("CF1237H.in","r",stdin); #endif scanf("%d",&Q); for (;Q;--Q) { scanf("%s",S+1),scanf("%s",T+1); n=strlen(S+1),tot=0,N=n/2; memset(sum,0,sizeof(sum)); memset(Sum,0,sizeof(Sum)); fo(i,1,N) a[i]=turn(S[i*2-1],S[i*2]),++sum[a[i]]; fo(i,1,N) b[i]=turn(T[i*2-1],T[i*2]),++Sum[b[i]]; if (sum[0]+sum[1]!=sum[0]+sum[1] || sum[2]!=Sum[2] || sum[3]!=Sum[3]) {printf("-1\n");continue;} Ls=-1,tot=0; if (sum[0]!=Sum[0]) { if (abs(sum[0]-sum[1])>abs(Sum[0]-Sum[1])) { fo(i,1,N) if (a[i]<=1) { --sum[a[i]],++sum[a[i]^1]; if (sum[0]==Sum[0]) {rev(a,i);ans[++tot]=i;break;} } } else { fo(i,1,N) if (b[i]<=1) { --Sum[b[i]],++Sum[b[i]^1]; if (sum[0]==Sum[0]) {rev(b,i);Ls=i;break;} } } } fo(i,1,N-1) { fo(j,i,N) if (a[j]==b[i]) { if (j>1) rev(a,j-1),ans[++tot]=j-1; rev(a,j),ans[++tot]=j; break; } } if (N>1) rev(a,N-1),ans[++tot]=N-1; if (Ls>-1) ans[++tot]=Ls; printf("%d\n",tot); fo(i,1,tot) printf("%d ",ans[i]*2); printf("\n"); } fclose(stdin); fclose(stdout); return 0; }