【CF1438D】Powerful Ksenia

题目

题目链接:https://codeforces.ml/problemset/problem/1438/D
\(n\) 个正整数 \(a_i\),\(1 \le a_i\le10^9\)

每次操作是选三个不同的下标 \(i,j,k\) ,让 \(a_i,a_j,a_k\) 都变成 \(a_i \oplus a_j\oplus a_k\) 也就是这三个数的异或和。

让你判断是否能在 \(n\) 次操作内,使这 \(n\) 个正整数的值变成相同的。

若能,第一行输出YES,第二行输出 \(m\) 表示操作数两,接下来 \(m\) 行每行三个整数,描述一次操作;

若不能,输出NO。

思路

由于 \(a\operatorname{xor} b\operatorname{xor} b=a\),所以当 \(n\) 是奇数的时候,考虑将序列变为 \(\frac{n-1}{2}\) 个两两相等的数,再将他们全部异或上最后一个数。
那么我们每次取任意三个数异或起来,将其中两个放做一组,剩余一个扔进序列中继续搞,这样就可以在 \(\frac{n-1}{2}\) 次操作达到目标。最后异或成同一个数仍然需要 \(\frac{n-1}{2}\) 次操作,总操作数为 \(n-1\) 次。
\(n\) 是偶数的时候,因为进行任意操作序列的异或和仍然不变,所以最终如果有解,序列异或和一定是 \(0\)
所以如果原序列异或和不为 \(0\) 直接无解,否则我们可以先将前 \(n-1\) 个数字按照奇数的方式做好,第 \(n\) 个数字最终一定等于第 \(n-1\) 个数字。操作次数为 \(n-2\)
时间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;

int n,xors;

int main()
{
	scanf("%d",&n);
	for (int i=1,x;i<=n;i++)
	{
		scanf("%d",&x);
		xors^=x;
	}
	if (!(n&1) && xors) return printf("NO"),0;
	if (!(n&1)) n--;
	printf("YES\n%d\n",n-1);
	for (int i=1;i<=n-2;i+=2)
		printf("%d %d %d\n",i,i+1,i+2);
	for (int i=1;i<=n-2;i+=2)
		printf("%d %d %d\n",i,i+1,n);
	return 0;
}
posted @ 2020-11-18 10:21  stoorz  阅读(135)  评论(0编辑  收藏  举报