CF1722G 题解
CF1722G 题解
题意
给定一个正整数 n,要求构造一个长度为 n 的数组,使得数组的奇数项的异或和等于偶数项的异或和。
有多组数据。
前置知识
位运算,知道 a⊕a=0,0⊕a=a。
思路
注意到,题目要求每个数各不相同,于是想到可以让数组为 1,2,3,⋯,n−1,an。前面几个为各不相同的数,最后一个简单处理下即可。
但是!这样会重复,an 可能会和前面的数重复,所以令 x=1⊕2⊕3⊕⋯⊕(n−3),则让数组为 1,2,3,⋯,n−3,218,219,x⊕218⊕219。于是,就快乐地 AC 啦~~~
等等,没结束,你还没告诉我这为啥就不重复了捏?
因为,打开计算器,发现 218=262144,218>2×105,所以,前面的 (n−1) 个数是互不相同的(因为 n⩽2×105),而 x⩽2×105,所以最后一个数是不等于前面的任何一个数的,而且它大于 219。
等等!我还有疑问,为啥这是正确的捏?
其实也非常简单,有前置知识,任意一个实数 a,有 a⊕a=0,0⊕a=a,而我们知道,和最后一项同奇偶的项数的异或和为 219⊕ 所有数字小于 218 且与最后一项异奇偶的所有数的异或和;和最后一项异奇偶的项数的异或和为 219⊕ 所有数字小于 218 且与最后一项异奇偶的所有数的异或和。两者相同。
再等等!我懂了结论的正确性了,但你是咋推出来的呢?
很简单,要学会偷懒!做题肯定想要特殊处理的少,那既然 1 个不行,那就试试 3 个呗!而异或要是两个数在二进制下有一位有且只有一个为 1 的情况下,就为 1,而大于一个数的数一定与这个数不同,于是就考虑大于 2×105 的 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现