CF1415D XOR-gun

CF1415D XOR-gun

二进制好题,真的只差一点点就做出来了嘤嘤嘤(本可以手撕一道CF2000)

就是要吃透二进制性质:

1、根据异或的运算法则,如果三个相邻数最高位二进制相同,比如 \(x, y, z\), 那么一定有 \(x > y \oplus z\)。则 \(ans = 1\)

2、根据二进制, \(< 1e9\) 的数最多只有 \(30\) 个二进制位。

综上,如果 \(ans > 1\),必有 \(n \le 60\)。否则 \(ans = 1\)

\(n \le 60\),怎么暴力做呢?把每次最高位变化的位置称为断点。

这就是我唯一没想通的地方。我想到了枚举断点,但以为断点有很多个。但其实最多对 \(2\) 堆数进行合并,因为只需要一处异常即可。所以枚举 \(3\) 个断点即可,时间按复杂度 \(O(n ^ 3)\)

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 2e5;
int a[N], s[N]; 
int n;
void Main(){ 
	cin >> n;
	F(i, 1, n){
		cin >> a[i];
		s[i] = s[i - 1] ^ a[i];
	}
	if(n > 60){
		cout << 1 << '\n';
	} 
	else{
		int ans = 100; 
		F(i, 1, n){
			F(j, i, n){
				F(k, j + 1, n){
					int cntl, vl, cntr, vr;
					if(j > i){
						cntl = j - i;
						vl = s[j] ^ s[i - 1];
					}
					else{
						cntl = 0;
						vl = a[i];
					}
					if(k > j + 1){
						cntr = k - j - 1;
						vr = s[k] ^ s[j];
					}
					else{
						cntr = 0;
						vr = a[k];
					}
					if(vl > vr){
						ans = min(ans, cntl + cntr);
					}
				}
			}
		}
		if(ans == 100){
			cout << -1 << '\n';
		}
		else{
			cout << ans << '\n';
		}
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T = 1;
	while(T --) Main(); 
	return fflush(0), 0;
}
posted @ 2026-09-01 21:49  superl61  阅读(2)  评论(0)    收藏  举报