BZOJ4245 二进制贪心

对于第i位 只有每段第i位都为0 结果才为0 所以要最小的话 从最高位开始判断是否可以为零 具体的求出前缀xor的值 如果第i位偶数个1 那就可以偶数个分一组 这样最后or的结果是0 在奇数个的位置打上标记 即不能在这里分开(这里分开的话or下来肯定是1) 扫完一遍如果 总标记+m-1<=n 那就有分成m段的方案 每一位这样贪心就能得到最小值

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500010;
int n,m,sum,tot;
ll ans,v[maxn];
int s[maxn];
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read(),m=read();
    int i,flag=0;
    ll j;
    for(i=1;i<=n;i++) v[i]=read();
    for(j=1ll<<62;j;j>>=1)
    {
        for(sum=0,i=1;i<=n;i++)  if(v[i]&j)  sum++;
        if(sum&1)   ans^=j;
        else
        {
            for(flag=sum=0,i=1;i<n;i++)
            {
                if(v[i]&j)  flag^=1;
                s[i]+=flag,sum+=(s[i]==1)&flag;
            }
            if(sum+tot+m>n)
            {
                ans^=j;
                for(flag=sum=0,i=1;i<n;i++)
                {
                    if(v[i]&j)  flag^=1;
                    s[i]-=flag;
                }
            }
            else    tot+=sum;
        }
    }
    cout<<ans<<endl;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值