CF1438D Powerful Ksenia
题解
异或性质
1^1=0
1^0=1
0^1=1
0^0=0
简单来说,同为0,异为1
模拟
操作:任意三个数可以变成这三个数异或和
目的:使序列都相同
可以尝试先模拟
当n=3时 直接进行1次操作
当n=4时
[x,y,z,w]
1次操作后
设s=x ^ y ^ z
[s,s,s,w]
此时 任意选三个数要么是 s,s,w或s,s,s
选s,s,s没有意义,s,s,w,则又等于w,w,w,此时[s,w,w,w]
接下来无论怎么操作,这个序列的数都不能想等
但当s=w时 序列即可相等 则当s!=w时 无论多少次操作皆不可能
当n=5时
[x,y,z,w,u]
1次操作,选前三个数
设s=x ^ y ^ z
[s,s,s,w,u]
2次操作,如果选s,s,w没有意义因为选了两个s,s只会把这个三个数又变成那个除了s的数
此时我们能选的三个数s,w,u
设k=s ^ w ^ u
操作后
[s,s,k,k,k]
耶 突然发现 这个时候 把s,s,k 一操作
3次操作
[k,k,k,k,k]
这个时候还没发现什么
继续啊
当n==6时
[a,b,c,d,e,f]
经过类似 当n==5时的序列操作
[k,k,k,k,k,f]
此时类比n=3 和 n=4
当k==f时 仍有解
经过这几次模拟后
会发现当n为奇数时 一定有解
当n为偶数时 前n-1位数异或相同后的数与第n个数时,有解 否则无解
通过之前的模拟会发现
s ^ s ^ k =k(当然其实也是异或的性质
所以再看 n为奇数时
(
n
−
1
)
m
o
d
=
=
0
(n-1) mod ==0
(n−1)mod==0
则可以考虑 把n-1长度的序列 分为
n
−
1
2
\frac{n-1} {2}
2n−1个区间并使这个区间内数相同
那么目前的任务,使区间内的数相等
例如 [a,b,c,d,e,f,g] ——> [h,h,j,j,k,k,k]
[a,b,c,d,e,f,g]——>[h,h,h,d,e,f,g]——>[h,h,j,j,j,f,g]——>[h,h,j,j,k,k,k]
接下来再把任意区间和第n个数异或
[h,h,j,j,k,k,k]——>[k,k,j,j,k,k,k]——>[k,k,k,k,k,k,k]
可推k==j ^ f ^ g=h ^ d ^ e ^ f ^g=a ^ b ^ c ^ d ^ e ^ f ^ g
推广一下
当n为奇数时
先把每个区间内数相等 需要
n
−
1
2
\frac{n-1}{2} \quad
2n−1次操作
再把
n
−
3
2
\frac{n-3}{2}\quad
2n−3次数操作
总次数
n
−
3
2
+
n
−
1
2
=
n
−
2
\frac{n-3}{2}\quad+\frac{n-1}{2}\quad=n-2
2n−3+2n−1=n−2
当n为偶数时
则其操作与奇数
n
−
1
n-1
n−1几乎相同
加一个判断 是否前
n
−
1
n-1
n−1个异或和是否与第n个相同
即前n-1项异或 与 第n个数异或 等于 0
code
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n;int sum=0;
const int maxn=1e5+10;
int a[maxn];
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i],sum^=a[i];
if(!(n&1)) {//当n为偶数
if(sum){//前n-1位可当成n为奇数数时操作
//当且仅当第n位的数等于前(n-1)位异或成的数,此时sum=0
//偶数个按位异或的数相同
cout<<"NO"<<endl;
return 0;}
--n;
}
cout<<"YES"<<endl;
cout<<n-2<<endl;
for(int i=1;i<=n-2;i+=2) cout<<i<<" "<<i+1<<" "<<i+2<<endl;//使i,i+1位上的数相等,i%2==1
//使整个序列等于n,经过第一轮操作,n-2,n-1,n位上的数字都相等
//i只用循环到n-4位即可
for(int i=1;i<=n-4;i+=2) cout<<i<<" "<<i+1<<" "<<n<<endl;
return 0;
}
总结
本质是一道构造题
- 异或性质要清楚
- 尝试模拟计算过程
- 归纳
ZFY AK IOI