codeforces 1457 D. XOR-gun (构造)

题目链接:https://codeforces.com/contest/1457/problem/D

错误做法:以为只有连续异或一段数的情况,直接上\(trie\), wa 在 \(51\) 个点上
后来发现还有一种情况: 左边连续一段异或起来大于右边连续一段异或起来

正确做法:构造,序列中如果连续三个数最高位 \(1\) 位置相同,则可以通过异或后两个数一次满足条件
所以如果数列中超过了 \(60\) 个数,答案必定为 \(1\), 如果小于 \(60\) 个数,暴力即可

trie: (调了好久才调出来发现是错误做法。。)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n;
ll a[maxn];

int rt = 0, tot = 0;

struct Trie{
	int son[2];
	int pos;
}trie[maxn * 32];

void insert(int x, int l){
	int p = rt;
	for(int i = 31 ; i >= 0 ; --i){
		int c = (x >> i) & 1;
		
		if(!trie[p].son[c]){
			trie[p].son[c] = ++tot;
		}
		
		p = trie[p].son[c];
		trie[p].pos = l;
	}
}

int query_l(int x, int y){
	int p = rt;
	int res = -1;
	for(int i = 31; i >= 0 ; --i){
		int c = (x >> i) & 1;
		int g = (y >> i) & 1;
//		printf("%d %d %d\n", i, c, g);
		if(c == 1){
			if(g == 0){ // 两边都可以走 
				if(trie[p].son[0]){ // 异或值满足条件,记录一下答案, 向反方向探索 
					res = max(res, trie[trie[p].son[0]].pos); 
					if(trie[p].son[1]) p = trie[p].son[1];
					else return res;
//					printf("pos: %d\n", trie[trie[p].son[0]].pos); 
				} else{ // 目前异或值相等,继续向下寻找 
					if(trie[p].son[1]) p = trie[p].son[1];
					else return res;
				}	
			} else{ // 只能异或值为 1 才能相等,否则不满足条件 
				if(trie[p].son[0]){
					p = trie[p].son[0];
				} else{
					return res;
				} 
			}
		} else{
			if(g == 0){ // 两边都可以走 
				if(trie[p].son[1]){ // 异或值满足条件,记录一下答案, 无需向下探索 
					res = max(res, trie[trie[p].son[1]].pos); 
					if(trie[p].son[0]) p = trie[p].son[0];
					else return res;
//					printf("pos: %d\n", trie[trie[p].son[0]].pos); 
				} else{ // 目前异或值相等,继续向下寻找 
					if(trie[p].son[0]) p = trie[p].son[0];
					else return res;
				}	
			} else{ // 只能异或值为 1 才能相等,否则不满足条件 
				if(trie[p].son[1]){
					p = trie[p].son[1];
				} else{ // 否则不满足条件,直接返回不可能 
					return res;
				} 
			}
		}
//		printf("%d ", p);
	}
//	printf("\n");
	return res; 
}

int query_r(int x, int y){
//	printf("x:%d y:%d\n", x, y);
	int p = rt;
	int res = 1000000007;
	for(int i = 31; i >= 0 ; --i){
		int c = (x >> i) & 1;
		int g = (y >> i) & 1;
//		printf("%d %d %d\n", i, c, g);
		if(c == 1){
			if(g == 1){ // 两边都可以走 
				if(trie[p].son[1]){ // 异或值满足条件,记录一下答案, 无需向下探索 
					res = min(res, trie[trie[p].son[1]].pos); 
					if(trie[p].son[0]) p = trie[p].son[0];
					else return res;
//					printf("pos: %d %d\n", i, trie[trie[p].son[0]].pos); 
				} else{ // 目前异或值相等,继续向下寻找 
					if(trie[p].son[0]) p = trie[p].son[0];
					else return res;
				}	
			} else{ // 只能异或值为 0 才能相等,否则不满足条件 
//				printf("zhixing %d\n", trie[p].son[1]);
				if(trie[p].son[1]){
					p = trie[p].son[1];
				} else{
					return res;
				} 
			}
		} else{
			if(g == 1){ // 两边都可以走 
				if(trie[p].son[0]){ // 异或值满足条件,记录一下答案, 无需向下探索 
					res = min(res, trie[trie[p].son[0]].pos);
					if(trie[p].son[1]) p = trie[p].son[1];
					else return res;
//					printf("pos: %d %d\n", i, trie[trie[p].son[0]].pos); 
				} else{ // 目前异或值相等,继续向下寻找 
					if(trie[p].son[1]) p = trie[p].son[1];
					else return res;
				}	
			} else{ // 只能异或值为 0 才能相等,否则不满足条件 
				if(trie[p].son[0]){
					p = trie[p].son[0];
				} else{ // 否则不满足条件,直接返回不可能 
					return res;
				} 
			}
		}
//		printf("p : %d \n", p);
	}
	return res; 
} 

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 1 ; i <= n ; ++i) a[i] = read();
	
	int ans = 10000000;
	insert(0, 0);
	int sum = a[1];
	insert(a[1], 1);
	for(int i = 2 ; i <= n - 1; ++i){
		sum ^= a[i];
		int res = query_l(sum, a[i + 1]);
		if(res != -1) ans = min(ans, i - res - 1);
		insert(sum, i);
	}
//	printf("%d\n", ans);

	tot = 0;
	memset(trie, 0, sizeof(trie));
	
	insert(0, n + 1);
	sum = a[n];
	insert(a[n], n);
	
//	printf("%d\n", sum);
	for(int i = n - 1 ; i >= 2 ; --i){
		sum ^= a[i];
//		printf("%d: %d %d\n", i, sum, a[i - 1]);
		int res = query_r(sum, a[i - 1]);
		if(res != 1000000007) {
			ans = min(ans, res - i - 1);
//			printf("%d %d %d %d\n", i, res, ans, sum);
		}
		insert(sum, i);
	}
	
	printf("%d\n", ans == 10000000? -1: ans);
	
	return 0;
}
posted @ 2020-11-30 23:22  Tartarus_li  阅读(213)  评论(0编辑  收藏  举报