CF1722G Even-Odd XOR#817(div.4)

题目链接

https://codeforces.com/problemset/problem/1722/G

题意简述

题意很简单啦

样例

点击查看样例

image

分析

首先说几个异或运算的性质.异或运算满足交换律,结合律
并且,
\(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;
}
posted @ 2022-09-17 14:23  LZH_03  阅读(32)  评论(0编辑  收藏  举报