Solution
下面基本都是题解的中文翻译。
为了方便,称一个数的奇偶性为二进制表示中
1
1
1个数的奇偶性。
首先判掉无解,即
A
A
A与
B
B
B奇偶性相同,因为每次有一位不同,所以每次奇偶性会变。
下面用归纳法证明其他情况都是有解的。
n
=
1
n=1
n=1时显然有解,假设
n
=
k
n=k
n=k时有解,现在证明
n
=
k
+
1
n=k+1
n=k+1时也有解。
A
A
A和
B
B
B至少有一位不同,假设是第
x
x
x位,两个数同时去掉第
x
x
x位,得到
A
′
、
B
′
A'、B'
A′、B′的奇偶性是相同的。然后弄一个
C
C
C,使得其与
A
′
、
B
′
A'、B'
A′、B′的奇偶性都不同,比如
C
=
A
′
C=A'
C=A′异或
1
1
1,此时若
A
、
B
A、B
A、B有
n
n
n位,那么
A
′
、
B
′
、
C
A'、B'、C
A′、B′、C都只有
n
−
1
n-1
n−1位,我们可以得到
A
′
A'
A′到
C
C
C的长为
2
n
−
1
2^{n-1}
2n−1的排列的答案, 以及
C
C
C到
B
′
B'
B′的长为
2
n
−
1
2^{n-1}
2n−1的排列的答案。那么接下来就好办了,前
2
n
−
1
2^{n-1}
2n−1个数就是
A
′
A'
A′到
C
C
C的答案,然后把
A
A
A的第
x
x
x位插进去,后
2
n
−
1
2^{n-1}
2n−1个数就是
C
C
C到
B
′
B'
B′的答案,同样把
B
B
B的第
x
x
x位插进去。
代码也十分好写。以后要注意归纳法在构造题中的应用。
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
int o(int x)
{
int re=0;
while(x)re^=(x&1),x>>=1;
return re;
}
int n,A,B,ans[18][1<<17];
void solve(int k,int A,int B,int *a,int l,int r)
{
if(k==1){a[l]=A,a[r]=B;return;}
int C=A^B,t=(C&-C),mid=l+r>>1;
int tA=A%t+A/(t<<1)*t,tB=B%t+B/(t<<1)*t,tC=tA^1;
solve(k-1,tA,tC,ans[k-1],l,mid),solve(k-1,tC,tB,ans[k-1],mid+1,r);
for(int i=l;i<=mid;i++)
a[i]=ans[k-1][i]%t+ans[k-1][i]/t*(t<<1)+((A&t)?t:0);
for(int i=mid+1;i<=r;i++)
a[i]=ans[k-1][i]%t+ans[k-1][i]/t*(t<<1)+((B&t)?t:0);
}
int main()
{
n=read(),A=read(),B=read();
if(o(A)==o(B))return puts("NO"),0;
solve(n,A,B,ans[n],0,(1<<n)-1);
puts("YES");
for(int i=0;i<(1<<n);i++)printf("%d ",ans[n][i]);
}