CF1722G 题解
CF1722G 题解
题意
给定一个正整数 \(n\),要求构造一个长度为 \(n\) 的数组,使得数组的奇数项的异或和等于偶数项的异或和。
有多组数据。
前置知识
位运算,知道 \(a\oplus a=0,0\oplus a=a\)。
思路
注意到,题目要求每个数各不相同,于是想到可以让数组为 \(1,2,3,\cdots,n-1,a_n\)。前面几个为各不相同的数,最后一个简单处理下即可。
但是!这样会重复,\(a_n\) 可能会和前面的数重复,所以令 \(x=1\oplus2\oplus3\oplus\cdots\oplus(n-3)\),则让数组为 \(1,2,3,\cdots,n-3,2^{18},2^{19},x\oplus2^{18}\oplus2^{19}\)。于是,就快乐地 AC 啦~~~
等等,没结束,你还没告诉我这为啥就不重复了捏?
因为,打开计算器,发现 \(2^{18}=262144,2^{18}>2\times10^5\),所以,前面的 \((n-1)\) 个数是互不相同的(因为 \(n\leqslant2\times10^5\)),而 \(x\leqslant2\times10^5\),所以最后一个数是不等于前面的任何一个数的,而且它大于 \(2^{19}\)。
等等!我还有疑问,为啥这是正确的捏?
其实也非常简单,有前置知识,任意一个实数 \(a\),有 \(a\oplus a=0,0\oplus a=a\),而我们知道,和最后一项同奇偶的项数的异或和为 \(2^{19}\oplus\) 所有数字小于 \(2^{18}\) 且与最后一项异奇偶的所有数的异或和;和最后一项异奇偶的项数的异或和为 \(2^{19}\oplus\) 所有数字小于 \(2^{18}\) 且与最后一项异奇偶的所有数的异或和。两者相同。
再等等!我懂了结论的正确性了,但你是咋推出来的呢?
很简单,要学会偷懒!做题肯定想要特殊处理的少,那既然 \(1\) 个不行,那就试试 \(3\) 个呗!而异或要是两个数在二进制下有一位有且只有一个为 \(1\) 的情况下,就为 \(1\),而大于一个数的数一定与这个数不同,于是就考虑大于 \(2\times10^5\) 的 \(2\) 的指数幂,就出来啦~
哦,结束了,都懂了,上代码喽!
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long T,n,x,num=1<<18;//大于200005的第一个二次方幂。
int main(){
scanf("%lld",&T);
while(T--){
x=0;//注意初始化!
scanf("%lld",&n);
for(int i=1; i<=n-3; i++){
printf("%lld ",i);
x^=i;
}
printf("%lld %lld %lld\n",num,num<<1,x^num^(num<<1));
}
return 0;
}