D. XOR-gun 思维 + 前缀和
题目大意:
给你一个大小为 (n) 的不递减数组,你可以选择两个连续的两个数,然后把这两个数删掉,把他们的异或值放到这个位置来。问,最少经过多少次,使得这个数组变成一个不是不递减的序列。
题解:
- 首先,容易发现,如果有三个数的最高位是一样的,那么只需要一次就可以了
- 然后,如果 n > 60,那么一定会存在有三个数的最高位是一样的
- 所以就可以把 n 的范围,缩小到 60
- 最后就有两个策略:
- 第一种就是连续的一段异或即可,
- 第二种就是两个连续段
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn],sum[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i] = sum[i-1]^a[i];
if(n>60) printf("1
");
else {
int ans = 1e9;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
int now = sum[j]^sum[i-1];
if(now<a[i-1]||(j+1<=n&&now>a[j+1])) ans = min(ans,j-i);
// printf("i = %d j = %d now = %d %d ans = %d
",i,j,now,a[j+1],ans);
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
for(int k=j+1;k<=n;k++){
int x = sum[j]^sum[i-1],y = sum[k]^sum[j];
if(x>y) ans = min(ans, k - i - 1);
}
}
}
if(ans>=1e9) printf("-1
");
else printf("%d
",ans);
}
}