CF1438D Powerful Ksenia

若干个数,每次可以选择三个不同的数,将它们替换成它们的异或和。

要求在\(n\)次以内使得所有数相等。

要求输出方案。

\(n\le 10^5\)


想这题时最大的败笔是想着每一位拆开……

原来跟位运算有关的题目还有不拆位的啊……

先考虑\(n\)为奇数的情况:

假如有数\(a,b,b\),一次操作可以让它们变成\(a,a,a\)

所以考虑先通过一些操作,使得剩下一个数和若干对相同的数,然后就可以\(\frac{n-1}{2}\)次做了。

搞个队列,每次弹出三个数,操作它们,然后将其中两个配对,最后一个丢回去。于是\(\frac{n-1}{2}\)次就可以搞完这个过程。

当为偶数时,由于异或和不变,最后异或和为\(0\),所以如果一开始异或和不为\(0\)则无解。

有解时,对前\(n-1\)个做以上操作。然后发现剩下那个会magically和前面的一样。

(因为前面的已经相同,总共的异或和为\(0\)。)


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 100005
int n;
int a[N];
queue<int> q;
queue<pair<int,int> > p;
void work(int n){
	for (int i=1;i<=n;++i)
		q.push(i);
	printf("YES\n%d\n",n-1);
	while (q.size()>1){
		int x=q.front();q.pop();
		int y=q.front();q.pop();
		int z=q.front();q.pop();
		printf("%d %d %d\n",x,y,z);
		a[x]=a[y]=a[z]=a[x]^a[y]^a[z];
		p.push(make_pair(x,y));
		q.push(z);
	}
	int z=q.front();
	while (!p.empty()){
		printf("%d %d %d\n",z,p.front().first,p.front().second);
		p.pop();
	}
}
int main(){
	scanf("%d",&n);
	int x=0;
	for (int i=1;i<=n;++i)
		scanf("%d",&a[i]),x^=a[i];
	if (n&1)
		work(n);
	else{
		if (x)
			printf("NO\n");
		else
			work(n-1);
	}
	return 0;
}
posted @ 2020-11-15 21:36  jz_597  阅读(127)  评论(0编辑  收藏  举报