51Nod-1315-合法整数集

ACM模版

描述

描述

题解

一道很有意思的位运算题。这里主要是考验对位运算的理解。

首先,我们可以将集合中的数划分为两种数,第一是根本不需要删除的元素,第二种是可能删除的元素。

那么我们先来分析第一种,什么叫做不可能删除的元素呢?
经过观察可以发现,只有当(Y | X) > X时,这个元素一定不必删除,因为凡是含有这个元素的集合,Fun(SubS)一定会大于X,这是因为这个Y存在X的二进制位为0位,Y对应位为1。

接着我们来分析第二种可能需要删除的元素。这里我们需要举一个例子:
如样例:1、2、4、7、8,X=7,这里去除第一种元素,剩余1、2、4、7。
二进制分别为0001、0010、0100、0111,
那么他们能给对应的二进制位提供的1的数量分别是:0222;而7的二进制是0111,所以,这里出现了我们至少要保证X的某一位二进制的1,无法由集合内的数提供,也就是说,我们至少要删除两个。
(PS:这里每一个1集合内都能提供两次,所以只有删除两个才能使其中一个为0,例如0022、0202、0220)

当然,这道题的两种元素可以合并在一起考虑,最后多加一个判断而已。

代码

#include <iostream>

using namespace std;

int digit[33] = {0};    //  所有有可能需要删除的数的对应数位的和
int digitX[33];         //  X的二进制表示

int main(int argc, const char * argv[])
{
    int N, X;
    cin >> N >> X;

    //  将X转化为2进制
    int XX = X;
    int key = 0;
    while (XX)
    {
        digitX[key++] = XX % 2;
        XX /= 2;
    }

    int Y;
    int res = 55;
    for (int i = 0; i < N; i++)
    {
        cin >> Y;
        if ((Y | X) > X)    //  说明存在X的二进制位为0位,Y为1,不用考虑删除
        {
            continue;
        }
        int key = 0;
        while (Y)
        {
            digit[key++] += Y % 2;
            Y /= 2;
        }
    }
    for (int i = 0; i < 33; i++)
    {
        if (digitX[i] && !digit[i]) //  X的某二进制位为1,但是集合内数无法为此位提供1
        {
            res = 0;
            break;
        }
        if (digit[i])               //  删除能提供的最少的二进制位
        {
            res = res > digit[i] ? digit[i] : res;
        }
    }

    std::cout << res << '\n';
    return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值