PIPIOJ 1440: PIPI的位运算问题Ⅲ 位运算 贪心

http://pipioj.online/problem.php?id=1440
在这里插入图片描述
思路:依次读入 n n n个数字,设 t o b tob tob为一函数,它接受一个整型参数 x x x,返回 x x x的二进制表示(数组形式),因为 a i < = 1 0 18 a_i<=10^{18} ai<=1018 2 60 > 1 0 18 2^{60}>10^{18} 260>1018,我们可以通过以下方式计算出数组 s u m sum sum
s u m i = ∑ j = 0 n t o b ( a j ) [ i ] sum_i=\sum_{j=0}^ntob(a_j)[i] sumi=j=0ntob(aj)[i]
因为二进制具有性质 2 i > ∑ j = 0 i − 1 2 j 2^i>\sum_{j=0}^{i-1}2^j 2i>j=0i12j,根据贪心思想,显然要从高位向低位枚举,对于 s u m i sum_i sumi来说,具体可分为四种情况(不合法的情况也考虑在内):

  1. 偶数个0,偶数个1。
  2. 偶数个0,奇数个1。
  3. 奇数个0,偶数个1。
  4. 奇数个0,奇数个1。

做简要计算可知,对于异或操作,只要有奇数个1,这一位就是有贡献的;对于或操作只要有1,这一位就是有贡献的。那么思路就很明确了,我们希望 s u m i sum_i sumi都是奇数,若其是偶数,通过一次转换操作(k=k-1)即可将其变为奇数;唯一需要注意的情况是 s u m i = 0 sum_i=0 sumi=0,此时我们只能考虑把某个数的某位0变为1,然而这个操作是有限制的,只有之前出现过 s u m i > 0 sum_i>0 sumi>0这种情况才能应用该操作。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

using ll=long long;

ll v,ans,mask;
int n,k,sum[60];

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&v);
        mask=1;
        int idx=0;
        while(mask<=v)
        {
            if(v&mask)
                ++sum[idx];
            mask<<=1;
            ++idx;
        }
    }
    bool can_set_0to1=false;
    mask=1ll<<59;
    for(int i=59;i>=0;i--,mask>>=1)
    {
        if(sum[i])
        {
            ans+=mask;
            can_set_0to1=true;
            if(sum[i]&1)
                ans+=mask;
            else if(k)
                ans+=mask,--k;
        }
        else if(can_set_0to1&&k)
            --k,ans+=mask<<1;
    }
    printf("%lld\n",ans);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值