0
点赞
收藏
分享

微信扫一扫

数位思想


我们知道一个事实,把一个较大的数字转化成数位数组思考,很容易将一个大循环变成很小的循环。

这在解决某些问题的过程中可以发挥很大的作用,将时间压缩。

例子:​​http://www.51nod.com/onlineJudge/questionCode.html#!problemId=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.



分析:如果直接逐个枚举,那么2^50够我们受的了。但是如果,把那些很大的数字变成数位数组来思考,那么我们可以这样做:将有可能的数字(数字<=X, 且对应的二进制数位上如果X是0,那么该数字也应该是0)转成数位累加起来,最后,数字X二进制位上是1的,累加后的数位数值的最小值就是答案。

例子:

3 7

1 2 4 

数位:

1:0 0 1

2:0 1 0

4:1 0 0

累加后:1 1 1

7:1 1 1

最小的数位数值就是1


下面的代码应该不用看了。。。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=55;
int bit[35];
void solve(int a){
int dex=1;
while(a){
if(a&1) bit[dex]++;
dex++;
a>>=1;
}
}
int length(int a){
int ans=0;
while(a){
a>>=1;
ans++;
}
return ans;
}
int main()
{
int n,x;
while(cin>>n>>x){
memset(bit,0,sizeof(bit));
int a;
int len=length(x),ans=0x3f3f3f3f;
for(int i=1;i<=n;i++){
scanf("%d",&a);
if(a<=x) {
bool flag=1;
for(int i=1;i<=len;i++){
if(!(x&(1<<(i-1)))&&(a&(1<<(i-1)))){ flag=0;break; }
}
if(flag)solve(a);
}
}

for(int i=1;i<=len;i++){
if(x&(1<<(i-1))){
ans=min(ans,bit[i]);
}
}
printf("%d\n",ans);
}
return 0;
}



举报

相关推荐

0 条评论