CF1573D D. Xor of 3 | 2500

很不错的一道构造

题目传送门


题意

给定一个01序列, 每次可以选择相邻的三个数, 将他们异或起来, 并让这三个数都等于异或结果。
每次操作用一个数x表示, 表示将x, x+1, x+2 异或起来
求一个长度不超过n的操作序列使得序列中每个数都等于0, 或者输出无解
保证只要能让所有数都等于0, 则存在合法操作序列

题解

首先我们考虑有奇数个1, 那么显然无解
这时候我们考虑从第一个1开始, 每次消掉第一对1(最前面两个1)
--这时候对于每一对1分两种情况

-- · 中间有奇数个0
比如10001、101 , 这种可以直接消掉
假设第一个1位置为x, 那么可以进行x, x+2, x+4....., 使得变成中间只有一个0
10001 -> 11101
然后消掉最后三个, 再一直往前消即可。

-- · 中间有偶数个0
这种显然无法直接整个消掉, 可以让他先全部变成1, 这时候如果左边或右边有一个0, 就可以消掉, 否则无解
比如1001 -> 1111 假设 原序列是10010, 右边有一个0, 那么现在11110可以消掉


实现

还是不好实现的,这里给出我的实现

如果第一个数是0, 直接往后消, 奇数直接消, 偶数前面有0能消
否则第一个数是1, 如果第一对是奇数情况, 直接消掉, 变第一种情况
否则第一对是偶数, 暂时不管第一对, 先把后面的消了, 这时候后面就有了0, 再消第一对
如果后面消不掉, 那么显然无解

具体不懂看代码
solve(x) 表示将x及以后的全消掉, return1表示能消掉, 否则不能.

**#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

int read(){
	int num=0, flag=1; char c=getchar();
	while(!isdigit(c) && c!='-') c=getchar();
	if(c=='-') flag=-1, c=getchar();
	while(isdigit(c)) num=num*10+c-'0', c=getchar();
	return num;  
}

const int N = 200505;
int T, n;
int a[N], nex[N];

vector<int> ans;
int solve(int x){
	if(x > n) return 0;
	if(nex[x] == 0) return 1;
	if( a[x] == 0 || (nex[x]-x-1)%2 ){
		if(a[x]==0) x = nex[x];
		while(x){
			if((nex[x]-x-1)%2){
				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{
				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]];
		}return 1;
	}else{
		if(solve(nex[x]+1)){
			for(int i=x; i+2<nex[x]; i+=2){
					ans.push_back(i);
			}
			for(int i=nex[x]+1; i-2>=x; i-=2){
				ans.push_back(i-2);
			}
			return 1;
		}else return 0;
	}
}

int main(){
	T=read();
	while(T--){
		n = read();
		for(int i=1; i<=n; i++) a[i] = read();
		int las = 0;
		int cnt = 0;
		for(int i=n; i>=1; i--){
			nex[i] = las;
			if(a[i]) las = i, cnt++;
		}
		if(cnt % 2) {
			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");
	}
	return 0;
}
**
posted @ 2021-09-23 15:52  ltdJcoder  阅读(153)  评论(0编辑  收藏  举报