CF1438D Powerful Ksenia(构造题)

洛谷传送门


解题思路

很经典的一个构造题。

从异或的性质入手:a^a^b=b。

于是我们就有了将其变成同一个数的一个策略:
若原来能化成aabbccc这样的一个数列,则可以在345、123位置依次进行一次操作,将其全部变为c。
而这个数列的形式也很容易达到。
从前往后以此在123、345、567进行一次操作即可。

当然这是奇数的情况,一定有解。

偶数却不一定有解。
还是用上述方法,我们发现最后会剩下一个元素。
所以当剩下的最后一个元素等于前面的元素,则一定有解。
这是只需要处理前n-1个数,当做奇数情况来做即可。

如何判断偶数情况是否有解呢?
我们发现当把三个数都变成其异或和时,整个数列的异或和是没有变的。
所以当偶数个数字时,若整个序列的异或和为0,则有解,否则无解。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int n,a[maxn],cnt,ans[maxn][4];
long long sum;
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],sum^=a[i];
	if((n&1)==0&&sum!=0){
		cout<<"NO"<<endl;
		return 0;
	}
	cout<<"YES"<<endl;
	if((n&1)==0) n--;
	for(int i=1;i<=n-2;i+=2){
		ans[++cnt][1]=i;
		ans[cnt][2]=i+1;
		ans[cnt][3]=i+2;
	}
	for(int i=n-2;i>=3;i-=2){
		ans[++cnt][1]=i;
		ans[cnt][2]=i-1;
		ans[cnt][3]=i-2;
	}
	cout<<cnt<<endl;
	for(int i=1;i<=cnt;i++){
		cout<<ans[i][1]<<" "<<ans[i][2]<<" "<<ans[i][3]<<endl;
	}
    return 0;
}