您的位置:首页 > 其它

51Nod-1315-合法整数集

2016-08-04 01:46 330 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  位运算 二进制