您的位置:首页 > 其它

51nod 1315 合法整数集问题(预处理)

2017-05-27 18:21 288 查看

1315 合法整数集

一个整数集合S是合法的,指S的任意子集subS有Fun(SubS)!=X,其中X是一个固定整数,Fun(A)的定义如下:
A为一个整数集合,设A中有n个元素,分别为a0,a1,a2,...,an-1,那么定义:Fun(A)=a0 or a1 or ... or an-1;Fun({}) = 0,即空集的函数值为0.其中,or为或操作。
现在给你一个集合Y与整数X的值,问在集合Y至少删除多少个元素能使集合Y合法?

例如:Y = {1,2,4},X=7;显然现在的Y不合法,因为 1 or 2 or 4 = 7,但是删除掉任何一个元素后Y将合法。所以,答案是1.

Input
第一行两个整数N,X,其中N为Y集合元素个数,X如题所述,且1<=N<=50,1<=X<=1,000,000,000.
之后N行,每行一个整数yi,即集合Y中的第i个元素,且1<=yi<=1,000,000,000.


Output
一个整数,表示最少删除多少个元素。


Input示例
5 7
1
2
4
7
8


Output示例
2


题解:这是一道二进制的题目,只要想到二进制数如果某一位的1无法出现那么这个数就凑不出来的原理。将集合里的所有元素化为二进制然后加起来就知道每一位1出现的次数arr[i],这样只要对x的二进制每一位做一个询问,如果是1的话,尝试将集合中所有可能出现1的数删掉,也就是arr[i]的值,如果是0,则是删掉n-arr[i]个数,然后一直取最小就是答案。数据处理时候要注意在x某位为0的时候,如果该元素为1则删掉,不要加入统计的总数中,考虑例子x=101,有两个元素为111,001就明白了。

代码:
#include<iostream>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<cstring>
#include<cstdio>
#include<utility>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int Max = 1e6+5;
const int mod = 1e9+7;
const int Hash = 10000;
const int INF = 1<<30;
const ll llINF = 1e18;

int n, x, cnt, counter;//cnt记录集合中元素的二进制位数,counter记录x的二进制位数
int arr[40], temp[40], aim[40];
void binary(int a)
{
while( a )
{
temp[cnt++] = a%2;
a /= 2;
}
}
int main( )
{
//freopen("input.txt", "r", stdin);
while(~scanf("%d%d", &n, &x))
{
memset(arr, 0, sizeof(arr));
memset(temp, 0, sizeof(temp));
int k;
counter = 0;
binary(x);
counter = cnt;
memcpy(aim, temp, sizeof(int)*counter);//aim储存x的二进制序列
for(int i=0; i<n; i++)
{
scanf("%d", &k);
cnt = 0;
binary(k);
int flag = 0;
for(int j=0; j<cnt; j++)
if(aim[j]-temp[j] == -1)
flag = 1;
if(flag)//这个元素不管怎么做或操作都不会和x相等,所以不要统计在内,否则会判断出错
continue;
for(int i=0; i<cnt; i++)
arr[i] += temp[i];
}
int ans = INF;
for(int i=0; i<counter; i++)
{
if(aim[i] == 1)
ans = min(ans, arr[i]);
else
ans = min(ans, n-arr[i]);
}
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  51nod ACM 博客