这题只能说不看题解真写不出来(可能是因为我没有脑子吧...
可以证明一下题解:
1.如果所有数异或起来不为0,则输出NO
首先我们发现三个数里面之后有一个1的时候,会变成三个1。如果有两个1的话,会变成0个1。我们发现其奇偶性是不会改变的。
2. 对于奇数情况,我们先选择 1, 3, 5, ..., n-2,之后选择n-4, n-6, ...., 3, 1。
首先如果选择 1, 3, 5, ..., n-2的话,能保证an, an-1, an-2都是0, 并且对于所有的偶数位置, ai = ai-1。
给出证明:
如果奇数个数异或起来为0的话,这说明有偶数个1,以及奇数个0。
因为操作不改变奇偶性,所以一定会存在011或者000这种情况,操作之后就变成000了,之后一旦出现000这种情况之后,后面其实就都是0了。
之后这样选择之后,剩下的数列就变成了ai = ai-1。 (可以操作看看
(证毕
于是剩下的都是连续的11,之后我们倒着操作就行了。
3. 对于偶数情况,我们只需要将他分成两个奇数情况,就可以了。如果没有就输出NO。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int inf = 0x3f3f3f3f; ///1061109567 const int maxn = 2e6 + 10; int n; vector<int> opt; int a[maxn]; void solve(int l, int r) { for (int i = l; i+2 <= r; i += 2) opt.push_back(i); for (int i = r-4; i >= l; i -= 2) opt.push_back(i); } void print() { puts("YES"); printf("%d ", opt.size()); for (auto i : opt) printf("%d ", i); puts(""); } int main() { int T; scanf("%d", &T); while (T--) { opt.clear(); int n; scanf("%d", &n); int sum = 0; for (int i = 1; i <= n; ++ i) { scanf("%d", &a[i]); sum ^= a[i]; } if (sum == 0) { if (n % 2) { solve(1, n); print(); } else { sum = 0; for (int i = 1; i <= n; ++ i) { sum ^= a[i]; if (i % 2 == 1 && sum == 0) { solve(1, i); solve(i+1, n); print(); break; } if (i == n) puts("NO"); } } } else puts("NO"); } return 0; } /* 5 5 0 0 1 1 2 5 3 1 1 */