传送门:
https://atcoder.jp/contests/agc031/tasks/agc031_c
考虑把x xor y,问题变成从0->x xor y
因为 2 n − 1 2^n-1 2n−1是奇数,所有 x x o r y x~xor~y x xor y有偶数个1无解。
由于我们任意交换一下位是没有关系的,所以考虑就是要构造出:
000 … − > 111 ( k ( k 奇 数 ) 个 1 ) 00 … … 000…->111(k(k奇数)个1)00…… 000…−>111(k(k奇数)个1)00……
记 s ( n , k ) s(n,k) s(n,k)表示有k个1时的答案。
当k=1时,显然有:
强制第一位为0,后面任意走完,可以通过n-1,k任意的情况推来
然后把第一位改为1,后面的倒着走即可走回后面全0
k>=3时
考虑固定第一位为0,后面走 s ( n − 1 , k − 2 ) s(n-1,k-2) s(n−1,k−2)
把第一位改为1,然后现在把后面的位视为全0(走的时候异或一下即可),走s(n-1,1),注意1的位置要移到n-k+1那里去。
#include
#include
#include
#include
#include
#define ll long long
#define db double
#define ld long double
#define pp printf
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define pb push_back
#define sz size()
using namespace std;
vector<int> a[18][18];
int z[1 << 18];
int us[20], to[20];
void zh(int x, int y, int n) {
ff(i, 0, n) us[i] = 0;
ff(i, 0, n) {
ff(j, 0, n) if((x >> i & 1) == (y >> j & 1) && !us[j])
{ us[j] = 1; to[i] = j; break;}
}
ff(i, 0, 1 << n) {
int s = 0;
ff(j, 0, n) s += (i >> j & 1) * (1 << to[j]);
z[i] = s;
}
}
int n, x, y, c;
void pr(int x, int n) {
fd(i, n - 1, 0) pp("%d", x >> i & 1); pp(" ");
}
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
n = 17;
a[1][1].pb(0); a[1][1].pb(1);
fo(i, 2, n) {
int mx = 1 << (i - 1);
ff(k, 0, a[i - 1][1].sz)
a[i][1].pb(a[i - 1][1][k]);
fd(k, a[i - 1][1].sz - 1, 0)
a[i][1].pb(a[i - 1][1][k] + mx);
for(int j = 3; j <= i; j += 2) {
ff(k, 0, a[i - 1][j - 2].sz)
a[i][j].pb(a[i - 1][j - 2][k]);
int h = a[i - 1][j - 2][a[i - 1][j - 2].sz - 1];
zh(1 << (i - 2), 1 << (i - j), i - 1);
ff(k, 0, a[i - 1][1].sz)
a[i][j].pb((z[a[i - 1][1][k]] ^ h) + (1 << (i - 1)));
}
}
scanf("%d %d %d", &n, &x, &y);
ff(i, 0, n) c += (x ^ y) >> i & 1;
if(c % 2 == 0) {
pp("NO\n"); return 0;
}
pp("YES\n");
zh(a[n][c][a[n][c].sz - 1], x ^ y, n);
ff(k, 0, a[n][c].sz) pp("%d ", z[a[n][c][k]] ^ x);
}