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;
}
**


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM