CF1572B. Xor of 3
题意:
给你个01序列,你有一种操作:每次选位置x,然后位置x,x+1,x+2的值变为三者的异或值。
现在要让所有的数都等于0,请输出存在的合法操作序列
题解:
首先如果有奇数个1,显然是无解的
此时我们从第一个1开始考虑,成对考虑消除1(因为这样异或为0),每次消除掉第一对1
如果两个1之间有奇数个0:
比如10001,100000001,这种是可以直接消掉的
就拿100000001来说,假设第一个1的位置为x,那我们可以依次操作x,x+2,x+4,…,(x<长度),此时序列为:111111101,然后操作x+6就得到111111000,然后再倒着执行x+4,x+2…这样就都变成0
如果两个1之间有偶数个0
这样是不能和上面一样直接消除的,可以先全部变成1,然后需要借助外面的0,也就是如果左边或右边有一个0,就可以消除,否则无解
比如1001 -> 1111 假设 原序列是10010, 右边有一个0, 那么现在11110可以消掉
实现起来挺麻烦的
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
bool Handsome;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...);
}
template <typename T> inline void write(T x)
{if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0');
}
void rd_test(bool &Most)
{
#ifdef ONLINE_JUDGE
#elseprintf("%.2lfMB\n",(&Most-&Handsome)/1024.0/1024.0);startTime = clock ();freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#elseendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=2e5+9;
int a[maxn],nex[maxn];
vector<int>ans;
int n;
bool Most;
int solve(int x){if(x>n)return 0;if(nex[x]==0)return 1;if(a[x]==0||(nex[x]-x-1)%2){//如果当前位置是0,或者中间有奇数个1 if(a[x]==0)x=nex[x];//找到后面最近1的位置 while(x){if((nex[x]-x-1)%2){//中间奇数个1,内部直接消 int i;for(i=x;i+2<nex[x];i+=2)ans.push_back(i);for(;i>=x;i-=2)ans.push_back(i);}else {//借助左边的0消除 for(int i=x;i+2<nex[x];i+=2)ans.push_back(i);for(int i=x-1;i+2<=nex[x];i+=2)ans.push_back(i);}x=nex[nex[x]];//下下一个1的位置(因为1都是成对处理) }return 1; }else{//因为中间有偶数个1且当前不是0,所以需要判断后面能否出现0 if(solve(nex[x]+1)){for(int i=x;i<nex[x]-2;i+=2)ans.push_back(i);for(int i=nex[x]+1;i-2>=x;i-=2)ans.push_back(i-2);return 1;}elsereturn 0; }
}
int main()
{rd_test(Most);int t;read(t);while(t--){read(n);for(int i=1;i<=n;i++)read(a[i]);int las=0;int cnt=0;for(int i=n;i>=1;i--){nex[i]=las;if(a[i])//如果非0,记录位置{las=i;cnt++;} }if(cnt%2)//如果奇数个1{printf("NO\n");continue; }ans.clear();if(solve(1)){printf("YES\n%d\n", ans.size());for(int i=0; i<ans.size(); i++) {printf("%d ", ans[i]);}printf("\n");} else printf("NO\n");}//Time_test();
}