【题解】异或
题面
问题描述
题目背景
\(\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.in
和 xor/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\),所以我们珂以得到:
那么,对于一个分段 \([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\) 咯~
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.
—— · EOF · ——
真的什么也不剩啦 😖