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

浙公网安备 33010602011771号