这题大概是noip难度,为什么CF上会评到3200?qwq
首先不难想到把两个字符压成一个来处理,大概就是:
0001100010->00 01 10 00 10
如果初始串中“00”的个数不等于目标串中“00”的个数,显然无解。对于“11”,也一样。
我们从第一组(目标串两个字符为一组)开始,依次匹配,具体来说,如下:([]里的字符是匹配好的字符,{}为这一次翻转的区间)
初始串:1001100011
目标串:00 11 01 01 10
目标串第一组字符是“00”,从初始串中找到“00”,并将其翻转到最前面。
目前:1001100011->{00011001}11->[00]01100111
目标:00 11 01 01 10
目标串第二组字符是“11”,从目前串中找到“11”,将其与已匹配好的“00”连在一起,再把它们翻到最前面。
目前:[00]01100111->{10011000}11->{1100011001}->[1100]011001
目标:00 11 01 01 10
这时大家可能会疑惑:前面四个字符不匹配呀?要不要再翻转一次使它们匹配?答案是不需要(原因见下文)。
继续匹配:目标第三组字符是“01”,从从目前串中找到“01”(如果有多个则随便找一个,如果没有?待会再说),将其与已匹配好的“0011”连在一起,再把它们翻到最前面。
目前:[1100]011001->{0011}011001->{101100}1001->[101100]1001
目标:00 11 01 01 10
继续匹配。
目前:[101100]1001->{01001101}01->{1010110010}->[10101100]10->{00110101}10->[00 11 01 01 10]
目标:00 11 01 01 10
匹配成功了!大功告成!可以看到,我们先将前2k个字符“倒序匹配”(目前状态前2k个字符反过来就是目标状态前2k个字符),再将前2(k+1)个字符“倒序匹配”,一直这么下去,直到匹配完成。示意图前2k个字符是"000110",x是两个字符“00”,"..."表示尚未匹配的字符)
当前状态:[011000]...(x)...->{...000110}(x)...->
{(x,011000...)...}->[x,011000]...
目标状态:(000110,x)...
但是,在匹配第i组字符的时候,找不到对应的字符怎么办?举个例子,i=3。
当前状态:[0011]100010
目标状态:11 00 01 10 00
目标第3组字符是“01”,可是当前状态中没有一组字符是“01”,怎么办呢?
注意到对于每一组字符,匹配前后当前串中未匹配字符中“01”和“10”不会颠倒(就是“01”匹配后还是“01”,“10”同理,具体可以回顾之前的匹配过程)。于是,我们只要想办法是初始串中“01”的个数和目标串中“01”的个数相同即可。方法很简单,翻转初始串和目标串个一次即可。怎么翻转目标串呢?打上标记,把初始串翻转成翻转后的目标串,然后再变成翻转前的目标串就好了。很明显,可以通过翻转初始串和目标串各至多一次来使两串中“01”的个数相等(感性理解即可)。
最后总结一下,先预处理,再挨个匹配,最后输出方案就可以了。
明显这么做翻转次数不会超过n+1次(预处理两次,匹配每两个字符两次,最后一组字符一次)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int _abs(int x){return x>0?x:-x;} int n,m,q,v; struct Pair{ bool A,B; }s[2000],t[2000]; char c1,c2; int cnt[8],ans[4005]; int s0[2000],s1[2000]; int t0[2000],t1[2000]; void read(void) { while((c1=getchar())=='\n'||c1==' '); c2=getchar(); s[n].A=c1-'0'; s[n++].B=c2-'0'; while((c1=getchar())!='\n'&&c1!=' '){ s[n].A=c1-'0'; s[n++].B=getchar()-'0'; } while((c1=getchar())=='\n'||c1==' '); c2=getchar(); t[m].A=c1-'0'; t[m++].B=c2-'0'; while((c1=getchar())!='\n'&&c1!=' '){ t[m].A=c1-'0'; t[m++].B=getchar()-'0'; } return; } inline void reverseS(int i) { ans[++q]=(i+1)<<1; for(int j=0;(j<<1)<=i;j++){ swap(s[j],s[i-j]); swap(s[j].A,s[j].B); if((j<<1)!=i) swap(s[i-j].A,s[i-j].B); } return; } inline void reverseT(int i) { for(int j=0;(j<<1)<=i;j++){ swap(t[j],t[i-j]); swap(t[j].A,t[j].B); if((j<<1)!=i) swap(t[i-j].A,t[i-j].B); } return; } inline void debug(void) { for(int i=0;i<n;i++) printf("%d%d ",s[i].A,s[i].B); putchar('\n'); for(int i=0;i<n;i++) printf("%d%d ",t[i].A,t[i].B); putchar('\n'); printf("--------------------------\n"); return; } inline void init(void) { s0[0]=t0[0]=s1[0]=t1[0]=0; for(int i=0;i<n;i++){ if(i>0){ s0[i]=s0[i-1]; s1[i]=s1[i-1]; t0[i]=t0[i-1]; t1[i]=t1[i-1]; } if(s[i].A==0&&s[i].B==1) s0[i]++; if(s[i].A==1&&s[i].B==0) s1[i]++; if(t[i].A==0&&t[i].B==1) t0[i]++; if(t[i].A==1&&t[i].B==0) t1[i]++; } return; } inline void rev(void) { if(s0[n-1]==t0[n-1]) return; for(int i=0;i<n;i++){ if(s0[n-1]-s0[i]+s1[i]==t0[n-1]){ reverseS(i); return; } if(s0[n-1]==t0[n-1]-t0[i]+t1[i]){ reverseT(v=i); return; } for(int j=0;j<n;j++) if(s0[n-1]-s0[i]+s1[i]==t0[n-1]-t0[j]+t1[j]){ reverseS(i); reverseT(v=j); return; } } } inline int find(int x) { for(int i=x;i<n;i++) if(s[i].A==t[x].A&&s[i].B==t[x].B) return i; return -1; } void solve(void) { n=m=0; q=v=-1; memset(cnt,0,sizeof(cnt)); read(); for(int i=0;i<n;i++){ cnt[s[i].A*2+s[i].B]++; cnt[t[i].A*2+t[i].B+4]++; } if(cnt[0]!=cnt[4]||cnt[3]!=cnt[7]||cnt[1]+cnt[2]!=cnt[5]+cnt[6]){ printf("-1\n"); return; } init(); rev(); for(int i=0;i<n;i++){ int t=find(i); if(t>0) reverseS(t-1); if(i!=n-1) reverseS(t); } if(v!=-1){ reverseS(v); reverseT(v); } printf("%d\n",q+1); for(int i=0;i<=q;i++) printf("%d ",ans[i]); putchar('\n'); return; } int main(void) { int T; scanf("%d",&T); while(T--) solve(); return 0; }