题意
给出一个长度为n的01序列,每次操作可以选择一个位置(i),然后将(a_i,a_{i + 1},a_{i + 2})均变成(a_i otimes a_{i + 1} otimes a_{i + 2}),找出一种操作方式,使得用不超过n次操作可以把整个序列变成0。如果不存在就输出NO
思路
显然只有当有偶数个1时才可能有解。
如果n是奇数,那就依次对(a_1,a_3...a_{n-2})进行操作,因为有偶数个1,而最后三个数相当于是整个序列异或起来,所以(a_n=a_{n-1}=a_{n-2}=0),而且这样可以使得(a_i=a_{i+1}),然后只要依次对(a_{n-4},a_{n-6}...a_1)进行操作即可。
如果n是偶数,那就把这个序列拆成两个长度为奇数且异或和为0的序列,然后用上面的方法。如果不存在一种拆法满足上述条件,那么就一定无解。
代码
/*
* @Author: wxyww
* @Date: 2021-09-23 10:02:41
* @Last Modified time: 2021-09-23 15:15:07
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#include<cstring>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 200010;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int a[N],ans[N],cnt;
void solve(int l,int r) {
for(int i = l;i < r;i += 2) ans[++cnt] = i;
for(int i = r - 4;i >= l;i -= 2) ans[++cnt] = i;
}
int main() {
int T = read();
while(T--) {
cnt = 0;
int n = read();
int tmp = 0;
for(int i = 1;i <= n;++i) {
a[i] = read();
tmp ^= a[i];
}
if(tmp) {
puts("NO");continue;
}
if(n & 1) solve(1,n);
else {
int k = 0,bz = 0;;
for(int i = 1;i <= n;i += 2) {
k ^= a[i] ^ a[i - 1];
if(!k) {
solve(1,i);solve(i + 1,n);
bz = 1;break;
}
}
if(!bz) {
puts("NO");continue;
}
}
puts("YES");
printf("%d
",cnt);
for(int i = 1;i <= cnt;++i) printf("%d ",ans[i]);
puts("");
}
return 0;
}
/*
3
5
1 1 1 1 0
4
1 0 0 1
*/