搜索题

题目描述

小H是一个热爱出毒瘤题的女孩子。

小H按照老师要求出了一道搜索题。这是一道只有题目和搜索有关的题目。

现在你有一个长度为n的数列A,每个数为ai,你要将它分成m段,每段至少1个数。令每段的异或值为ci。

你需要最小化所有ci或起来的值。

题解

显然我们希望高位为0,那么我们就一位一位贪心下去。如果在保证之前的高位切得动的情况下,能切就切下去,如果能切出大于等于m块即可,因为任意几块合起来还是偶的。
介绍一个巧妙的代码实现。我们可以随时记着当前的答案,如果这个区间和答案与起来还是等于这个区间相当于这个区间上不存在不在答案上的1,有的话就被消了。

代码

#include <bits/stdc++.h>
#define maxn 500005
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
LL read(){
    LL res,f=1; char c;
    while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48);
    while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
    return res*f;
}
LL n,m,a[maxn],sum[maxn],ans;
bool check(){
    int num=0,lst=0;
    for(int i=1;i<=n;i++){
        if(((sum[i]^sum[lst])&ans)==(sum[i]^sum[lst])) num++,lst=i;
    }
    return num<m||lst^n; 
}
int main(){
    n=read(); m=read();
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]^read();
    ans=(1ll<<61)-1;
    for(int s=60;~s;s--){
        ans^=(1ll<<s);
        if(check()) ans|=(1ll<<s);
    }
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jarden_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值