D. XOR-gun 思维和 + 前缀

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\n");
    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\n",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\n");
        else printf("%d\n",ans);
    }
}
posted @ 2021-03-26 19:55  EchoZQN  阅读(76)  评论(0编辑  收藏  举报