CF1438D Powerful Ksenia

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

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

要求输出方案。

(nle 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
%d
",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
",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
",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
");
		else
			work(n-1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/13979516.html