思路
构造。
因为是对偶数位操作,有一个巧妙的转化:将每两位和为一位。令 为 , 为 , 为 , 为 。其中 翻转得到 , 翻转得到 。
如果有解,则 。
考虑从一个大问题转换为小问题。,猜测答案是用两个操作实现 ,再有一个灵活的额外操作。可以一个一个处理。
要找到一种方法使得在不改变其他结构的同时移动 。观察发现,我们可以实现两步将 换到 , 不改变结构的换到 。具体是操作 和 。
所以从后向前,设当前维护到 ,则 分别等于 。找到 且 ,执行上面操作即可。共 次操作。
现在问题是, ,我们要反转一次使 。
我们可以找到 中某个前缀,使得 ,翻转这个前缀。但也可能找不到,这时一定有 的某个前缀,使得 。这时翻转 的这个前缀得到 ,把 做成 再翻转这个前缀。
code
int n,a[maxn],b[maxn];
char s[maxn],t[maxn];
int sum[4];
vector<int> ans;
int aa[maxn],bb[maxn],nn;
bool check(){
if(ans.size()>nn+1)return 0;
for(int i:ans){
for(int j=1;j<=i/2;j++)swap(aa[j],aa[i-j+1]);
// for(int j=1;j<=nn;j++)cout<<aa[j];cout<<"\n";
}
// for(int i=1;i<=nn;i++)cout<<aa[i];cout<<"\n";
for(int i=1;i<=nn;i++)if(aa[i]!=bb[i])return 0;
return 1;
}
void work(){
scanf("%s%s",s+1,t+1);n=strlen(s+1);
nn=n;
for(int i=1;i<=n;i++)aa[i]=s[i]-'0',bb[i]=t[i]-'0';
for(int i=2;i<=n;i+=2)a[i/2]=(s[i-1]-'0')*2+s[i]-'0';
for(int i=2;i<=n;i+=2)b[i/2]=(t[i-1]-'0')*2+t[i]-'0';
n>>=1;
for(int i=1;i<=n;i++)if(b[i]==1||b[i]==2)b[i]=3-b[i];
sum[0]=sum[1]=sum[2]=sum[3]=0;
for(int i=1;i<=n;i++)sum[a[i]]++;
for(int i=1;i<=n;i++)sum[b[i]]--;
if(sum[0]||sum[3]||sum[1]+sum[2]){printf("-1\n");return ;}
ans.clear();int pos=0;
bool fl=(sum[1]==0);
for(int i=1;i<=n&&!fl;i++){
sum[1]-=(a[i]==1);sum[1]+=(a[i]==2);
if(!sum[1]){
ans.push_back(2*i);
for(int j=1;j<=i/2;j++)swap(a[j],a[i-j+1]);
for(int j=1;j<=i;j++)if(a[j]==1||a[j]==2)a[j]=3-a[j];
fl=1;
}
}
sum[1]=-sum[2];
for(int i=1;i<=n&&!fl;i++){
sum[1]+=(b[i]==1);sum[1]-=(b[i]==2);
if(!sum[1]){
pos=2*i;
for(int j=1;j<=i/2;j++)swap(b[j],b[i-j+1]);
for(int j=1;j<=i;j++)if(b[j]==1||b[j]==2)b[j]=3-b[j];
fl=1;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++)if(a[j]==b[n-i+1]){
if(j*2-2!=0)ans.push_back(j*2-2);
ans.push_back(j*2);
for(int k=j-1;k;k--)a[k+1]=a[k];
a[1]=b[n-i+1];
break;
}
}
if(pos)ans.push_back(pos);
printf("%lld\n",(int)ans.size());
for(int i:ans)if(i)printf("%lld ",i);
printf("\n");
// cout<<check()<<"\n";
}