分析
没有要求最小化步数,也就是与DP没多大关系,只需要考虑如何操作能一定在有限步数里面完成调整,这是构造题的一般思路。看到是位运算,就从位的角度分析,看能不能一定有策略每一步都接近b。
想到这里就很接近了,也就是用逐位调整的思想,看能不能每次改变至少确定一位,并且之后不会受到后面的影响。最后考虑无解的情况。
我们先考虑如何将a与b的第一个1对齐。先找到b的第一个1,然后用这个位置往前更新,每找到a的一个1(证明突出来了),就用a的最后一个1去异或它,因为后面全是0了,所以对于已经更新过的不会有任何影响。
对齐之后情况就比较简单了,向后逐个比对,有不一样的就用第一个1的位置去异或它(此时a[p]=b[p]了),因为是第一个1,对前面的不会有影响,每次至少能调整一位,时间复杂度n方。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int t,n,m,ff;
string s1,s2;
int a[1000010],b[1000010];
int ans[1000010],tot;
void update(int k)
{
ans[++tot]=k;
if(k>0)
{
for(int i=1;i+k<=n;i++) a[i]=a[i]^a[i+k];
}
else
{
k=-k;
for(int i=n;i>=k+1;i--) a[i]=a[i]^a[i-k];
}
}
int main()
{
cin>>t;
while(t--)
{
memset(ans,0,sizeof(ans));
tot=0;
cin>>n;
cin>>s1>>s2;
int cnta=0,cntb=0;
for(int i=1;i<=n;i++)
{
a[i]=s1[i-1]-48;
if(a[i]==1) cnta++;
}
for(int i=1;i<=n;i++)
{
b[i]=s2[i-1]-48;
if(b[i]==1) cntb++;
}
if((cnta&&!cntb)||(cntb&&!cnta))
{
cout<<-1<<endl;
continue;
}
int p=0;
for(int i=1;i<=n;i++)
{
if(b[i])
{
p=i;
break;
}
}
for(int i=p;i>=1;i--)
{
if(a[i]==b[i]) continue;
for(int j=n;j>=1;j--)
{
if(a[j]==1)
{
update(j-i);
break;
}
}
}
for(int i=p+1;i<=n;i++)
{
if(a[i]==b[i]) continue;
update(p-i);
}
cout<<tot<<endl;
if(tot==0) continue;
for(int i=1;i<=tot;i++) cout<<ans[i]<<' ';
cout<<endl;
}
return 0;
}