CF1722G Even-Odd XOR#817(div.4)
题目链接
https://codeforces.com/problemset/problem/1722/G
题意简述
题意很简单啦
样例
点击查看样例
分析
首先说几个异或运算的性质.异或运算满足交换律,结合律
并且,
\(a\) 异或 \(b\) 为 \(0\) \(\Leftrightarrow\) \(a=b\)
要使奇数项异或等于偶数项异或,当且仅当数组中所有元素异或为 \(0\)
下面我们要构造一个这样的数组
我们显然有 \(a\) 异或 \(a\) 为 \(0\)
只需要让前面一些元素任取(不妨从 \(1\sim n\)当中挨个取),设他们的异或值为 \(c\)
然后最后两个元素分别取 \(c\) 异或 \(a\) 和 \(a\) ( \(a\) 是固定的一个较大的数 ,后面再说说 \(a\) 的取值限制条件)
他们异或起来就是 \(c\) 异或 \((c\) 异或 \(a)\) 异或 \(a\) 显然为 \(0\)
注意特判 \(c\)为 \(0\) 的情况,若 \(c\) 为 \(0\) ,那么 \(c\) 异或 \(a\) 就是 \(a\) ,最后两个元素相等了.
此时只需要改动前面一个数(选一个没用过的数),那么 \(c\) 就不为 \(0\) 了,然后重新再取.
\(a\) 的取值的限制条件
本来想的是 \(a\) 取 \(n\) ,但是这样的话,和原来的数很接近,导致 \(c\) 异或 \(a\) 的结果可能在前面已经出现过,参见下例
\(Sample\ Input\)
1
6
\(Sample\ Output\)
1 2 3 4 2 6
所以把 \(a\) 取的大一点.可以直接取 \(a\) 等于 \(2147483647\)
或者观察一下题目: \(n\) 最大是 \(2e^5\) ,二进制最高位的1是从右往左第18位
那么只要让 \(a\) 取 \(1<<19\)就能保证 \(a\) 异或 \(c\) 的值大于 \(n-2\) (前n-2个数的取值) 了
01000000000000000000
\((1<<19)\) (左起第二位的数不受影响)
00110000110101000000
\(2\ e^5\)(只能在左起第三位开始变化)
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int res[200010];
int main()
{
//freopen("uva.txt","r",stdin);
int n;
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n-2;i++)
{
ans=ans^i;
res[i]=i;
//printf("%d ",i);
}
int a=2147483647;
if(ans==0)
{
ans^=res[1];
res[1]=2147483646;
ans^=res[1];
}
for(int i=1;i<=n-2;i++)
{
printf("%d ",res[i]);
}
printf("%d %d",ans^a,a);
return 0;
}