【题解】异或

题面

问题描述

题目背景

\(\operatorname{xor}\) 好,\(\operatorname{xor}\) 妙......

题目描述

小 L 喜欢异或,他觉得异或最好玩了。

小 Z 突然问了小 L 一个问题:

请构造出一个长度为 \(n\) 序列 \(a\),该序列满足给出的 \(m\) 个条件。

每个条件形如 x y,意味着 \(\bigoplus_{i=1}^x a_i=y\)(其中 \(\bigoplus\)c++ 语言中的 ^ 符号)。

小 L 脑子坏了,构造不出来,于是向聪明的你求助,你能帮帮他吗?如果没有符合条件的序列请输出 -1

输入格式

输入文件名为 xor.in

输入文件的第一行,包含两个整数 \(n,m\),表示序列的长度和条件个数。

接下来 \(m\) 行,每行两个整数 \(x,y\),意义如题面所示。

输出格式

输出文件名为 xor.out

输出文件只有一行,包含 \(n\) 个整数,表示你构造出的序列。

本题含有 Special Judge。
如果满足条件的序列有多个,你可以输出任意一个序列。

但是对于输出的每个元素必须满足 \(a_i\in [1,2\times 10^9]\)

Special Judge 将在下发文件里给出。

输入输出样例 1

xor.in
5 2
3 0
2 3
xor.out
1 2 3 1 3

见选手目录下的 xor/xor1.inxor/xor1.out

输入输出样例 1 说明

该序列必须要满足两个条件,\(a_1\operatorname{xor}a_2\operatorname{xor}a_3=0\)\(a_1\operatorname{xor}a_2=3\)

样例 1 的输出给出了一个符合条件的序列。

输入输出样例 2

xor.in
6 1
2 4
xor.out
6 2 4 3 1 4

见选手目录下的 xor/xor2.in 和 xor/xor2.out。

输入输出样例 3

xor.in
2 2
1 2
2 2
xor.out
-1

见选手目录下的 xor/xor3.in 和 xor/xor3.out。

数据规模与约定

对于 \(100\%\) 的数据,\(1\le n,m\le 10^6\)\(1\le x\le n\)\(0\le y\le 10^9\)

测试点编号 \(n\) \(m\)
\(1\sim 3\) \(\le 10\) \(\le 10\)
\(4\sim 10\) \(\le 2\times 10^3\) \(\le 2\times 10^3\)
\(11\sim 14\) \(\le 10^5\) \(\le 10^5\)
\(15\sim 16\) / \(1\)
\(17\sim 20\) / /

保证数据随机。

Solution

令人开心的是,全部输出 -1 可以得15分(看来真的是随机数据)


在这里,我们假设 \(\bigoplus_{i=1}^{x_1} a_i=y_1\) , \(\bigoplus_{i=1}^{x_2} a_i=y_2(x_1<x_2)\)

那么,\(y_2\) 一定等于 \(y_1\operatorname{xor}(\bigoplus_{i=x_1+1}^{x_2} a_i)\) .

所以,我们分段处理,只要 \(1\) ~ \(x_1\)\(x_1\) ~ \(x_2\) 是合法的,那么 \(1\) ~ \(x_2\) 就是合法的。

那么,怎么去构造每一段中的数呢?

我们想,对于一个数 \(r\) ,因为 \(r\operatorname{xor}r=0\) ,同时 \(0\operatorname{xor}r=r\),所以我们珂以得到:

\[\begin{matrix}\underbrace{r\operatorname{xor}r\operatorname{xor}r\operatorname{xor}...\operatorname{xor}r}\\x个r\end{matrix}=\begin{cases}r&x\bmod 2=1\\0&x\bmod2=0\end{cases} \]

那么,对于一个分段 \([x_1,x_2]\),怎样才能在不改变 \(a_{x_1}\) 的情况下(因为改变 \(a_{x_1}\) 后,前面分段的异或值可能会发生改变,不满足题目要求),让当前分段满足要求?

不妨设 \((x_2-x_1)\bmod 2=0\) .

现在我们要让 \(y_1\operatorname{xor}(\bigoplus_{i=x_1+1}^{x_2}a_i)=y_2\) ,也就是\(y_1\operatorname{xor}(\bigoplus_{i=x_1+1}^{x_2-1}a_i)\operatorname{xor} a_{x_2}=y_2\).

因为 \(x_2-x_1\) 是偶数,所以\(x_1,x_2\) 中间的一段,也就是 \((x_2-1)-(x_1+1)=x_2-x_1-2\) 也是偶数。

因为不能让答案为 \(0\),所以我们给中间那一段随便赋一个相同的值(设这个值为常量 \(yzk\)),参照上面的结论,得到\(y_2=y_1\operatorname{xor}(\bigoplus_{i=x_1+1}^{x_2-1}a_i)\operatorname{xor} a_{x_2}=y_1\operatorname{xor}0\operatorname{xor} a_{x_2}=y_1\operatorname{xor}a_{x_2}\)

因为 \(y_1\operatorname{xor}y_1=0\) , \(0\operatorname{xor}y_2=y_2\)

所以,我们只需要让 \(a_{x_2}=y_1\operatorname{xor}y_2\) 就可以了唔QwQ


but,以上都是 \((x_2-x_1)\bmod 2=0\) 的结果,如果四\((x_2-x_1)\bmod 2=1\) 的时候嘞?

我们还是把中间那一段赋成 \(yzk\) ,但是,这样就会还剩下一个 \(yzk\) 没有被抵消掉,这个时候,我们如何方便快捷地多添上或减去一个 \(yzk\) ,既使得 \(a_{x_1}\) 的值不会被改变,又让 \(a_{x_1+1}\) ~ \(a_{x_2-1}\) 的值不为 \(0\) 呢?

很简单,我们只要在 \(a_{x_2}\) 上多异或一个 \(yzk\) 就珂以啦!


好,以上是不输出 -1 的情况,那么,在什么样的条件下,我们珂以输出 -1 呢?

锵锵!答案是,在输入的值中,有 \(x_i=x_j\),并且 \(y_i\ne y_j\) 时我们就输出-1 。同一序列不可能产生两个不同的异或值对吧。

以及,当 \(x_i=x_j+1\),并且 \(y_i=y_j\) 时也要输出-1。当且仅当 \(b=0\) 时,\(a\operatorname{xor}b=a\) ,不满足题意。

还有,如果最终求得的答案中有任何一个数最后为 \(0\) 了,不满足题意,输出 -1

现在,我们就能华丽丽地获得 \(85\) 分了!

#include<cstdio>
#include<cstring>
#include<algorithm>
using std::sort;
const int yzk=233;//Special Judge大法好
const int maxn=1e6+5;
struct data{
	int x,y;
	bool operator<(const data q)const{
		return x<q.x;
	}
}a[maxn];
int n,m;
int ans[maxn],vis[maxn];
int main(){
	memset(vis,-1,sizeof(vis));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&a[i].x,&a[i].y);
		if((~vis[a[i].x])&&vis[a[i].x]!=a[i].y){
			puts("-1");
			return 0;
		}
		if(vis[a[i].x-1]==a[i].y){
			puts("-1");
			return 0;
		}
		vis[a[i].x]=a[i].y;
	}
	sort(a+1,a+m+1);//为了更方便的更新每一小段而不起冲突,我们先对 x 进行排序。
	for(int i=1;i<=n;++i)
		ans[i]=yzk;
	for(int i=1;i<=m;++i){
		ans[a[i].x]=a[i-1].y xor a[i].y;
		if((a[i].x-a[i-1].x-1)&1) //众所周知,如果 x 是中间的个数,x+1 才是总个数。
			ans[a[i].x]^=yzk;
	}
	for(int i=1;i<=n;++i){
		if(!ans[i]){
			puts("-1");
			return 0;
		}
	}
	for(int i=1;i<=n;++i)
		printf("%d ",ans[i]);
	return 0;
}

氮素!我们忽略了某种情况:

\(x_2-x_1\) 为奇数,并且 \(y_1=y_2\) 的时候,特别处理。

例如:

5 2
2 0
5 0

这组数据,会构造 \(yzk \ yzk \ 0 \ yzk \ yzk\),不符合条件,但这组数据本身又确实是珂以构造出答案的,我们对这组数据特判。我们定义 \(ly\) 为另一个随便的数,像这样构造:\(yzk \ \ yzk\operatorname{xor}ly \ \ 0\operatorname{xor}ly \ \ yzk \ \ yzk\)


以及,有一个毒瘤的数据会卡去重,各位勤劳的可以自行手写循环,我就用 \(STL\) 咯~

\(\operatorname{unique()}:\) 定义于头文件 \(algorithm\) ,提供指针 \(begin\)\(end\),对 \([begin,end)\) 中的元素去重后返回去重数组的 \(end\) 指针。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using std::sort;
using std::unique;
const int yzk=233;
const int ly=54088;
const int maxn=1e6+5;
struct data{
	int x,y;
	bool operator<(const data q)const{
		return x<q.x;
	}
	bool operator==(const data q)const{
		return x==q.x;
	}
}a[maxn];
int n,m;
int ans[maxn],vis[maxn];
int main(){
	memset(vis,-1,sizeof(vis));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&a[i].x,&a[i].y);
		if((~vis[a[i].x])&&vis[a[i].x]!=a[i].y){
			puts("-1");
			return 0;
		}
		if(vis[a[i].x-1]==a[i].y){
			puts("-1");
			return 0;
		}
		vis[a[i].x]=a[i].y;
	}
	sort(a+1,a+m+1);
	m=unique(a+1,a+m+1)-a-1;
	for(int i=1;i<=n;++i)
		ans[i]=yzk;
	for(int i=1;i<=m;++i){
		ans[a[i].x]=a[i-1].y xor a[i].y;
		if((a[i].x-a[i-1].x>=2&&(a[i].x-a[i-1].x-1)&1))
			ans[a[i].x]^=yzk;
		if(!ans[a[i].x]&&(a[i].x!=a[i-1].x+1)){
			ans[a[i].x]^=ly;
			ans[a[i].x-1]^=ly;
		}
	}
	for(int i=1;i<=n;++i){
		if(!ans[i]){
			puts("-1");
			return 0;
		}
	}
	for(int i=1;i<=n;++i)
		printf("%d ",ans[i]);
	return 0;
}

end.​

posted @ 2020-11-28 17:51  XSC062  阅读(110)  评论(0编辑  收藏  举报