CF1438D
首先,要发现两个性质。
1.一次操作其实相当于把三个数变为相同的一个数。
2.每次操作前后整个数列的异或和不变。
第一个性质比较显然,证明一下第二个性质。
设原来这三个数分别为 \(x\),\(y\),\(z\),
操作前,它们的异或和为 \(x \oplus y \oplus z\) ,
操作后,这三个数都变成了 \(x \oplus y \oplus z\) ,
它们的异或和仍然为 \(x \oplus y \oplus z\) 。
先考虑数列长度为奇数的情况。
首先,把相邻的三个数操作一下,每次操作的起点即为上次操作的终点。
操作后,整个数列就变为了若干段长度为2的相同的数,以及最后一段长度为3的相同的数。
这样,把最后一个数拿出来,与前面的每两个相同的数都做一次操作即可。
操作次数为 \(n-2\) 次,可以通过。
接下来,考虑数列长度为偶数的情况。
如果是有解的,且数列长度为偶数,那么最后整个数列的异或和一定为0。
根据上面的性质2,可以得到数列操作前的异或和也一定为0,同理,整个数列在每一步操作后的异或和也为0。
现在已经可以判断无解了。
若有解,考虑把最后一个数单独拿出来,把前面的 \(n-1\) 个数按照奇数的做法做一遍。
因为整个数列在每一步操作后的异或和一定为0,又因为数列的前 \(n-1\) 个数已经相等了,所以,它们也一定和最后一个数相等。
操作次数为 \(n-3\) 次。
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int n,a[N],sum;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum^=a[i];
if(n%2==0&&sum) puts("NO"),exit(0);
if(n%2==0) n--;
printf("YES\n%d\n",n-2);
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-4;i+=2) printf("%d %d %d\n",i,i+1,n);
return 0;
}