题目
题意概要
求一个非负整数集合
S
S
S ,其大小为
n
n
n ,其元素的异或和为
x
x
x 。集合内的数字不得超过一百万。
数据范围与约定
n
,
x
≤
1
0
5
n,x\le 10^5
n,x≤105 ,输出任意一组解即可。无解输出
N
O
\tt{NO}
NO 。
思路
数据范围很大, d p \tt{dp} dp 等都不那么可做。考虑构造一组解。
如果 n n n 是奇数,我们用这样一招:
- 初始化:先随便选 n n n 个不同的非负整数。
- 进行微调:如果将每个数字都异或上 p p p ,那么总异或和就会异或 p p p ,而且各个数字仍然互不相同。取 p = 2 m p=2^m p=2m 即可。
如果 n n n 是偶数,我们试着直接使用一个 x x x ,所以用 n − 1 n-1 n−1 构造异或和为零的情况,然后讨论一下。
- 如果这 n − 1 n-1 n−1 个数中不包含 x x x ,直接将 x x x 加入即可。
- 如果包含 x x x ,将 x x x 与另外一个数字一起异或一个足够大的数字(比如 2 18 2^{18} 218 )。
异或足够大的数字之后,该数字将不会与已有的数字相同。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0' or c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c and c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(long long x){
if(x > 9) writeint(x/10);
putchar((x%10)^48);
}
# define MB template < class T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }
const int MaxN = 1000005;
int n, a[MaxN];
void build(int want){
for(int i=1; i<=n; ++i)
want ^= (a[i] = i);
for(int i=1; i<=n; ++i)
a[i] ^= want;
} // 构造一组解。仔细思考即可明白。
int main(){
n = readint(); int want = readint();
if(n == 2 and want == 0){
puts("NO"); return 0;
} // 唯一的无解情况
if(n%2 == 1){
build(want);
puts("YES");
for(int i=1; i<=n; ++i)
printf("%d ",a[i]);
return 0;
}
-- n, build(0);
for(int i=1; i<=n; ++i)
if(a[i] == want){
a[i] ^= (1<<18);
if(i != 1)
a[1] ^= (1<<18);
else a[2] ^= (1<<18);
}
puts("YES");
for(int i=1; i<=n; ++i)
printf("%d ",a[i]);
printf("%d\n",want);
return 0;
}