• 1315 合法整数集(位运算+模拟)


    题目来源: TopCoder
    基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题
     收藏
     关注
    一个整数集合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
    #include<bits/stdc++.h>
    #include<cstdio>
    const int maxn = 55;
    const int M = 0x3f3f3f3f;
    using namespace std;
    
    int a[maxn];
    int vis[maxn];
    int dis[maxn];
    int logo[maxn];
    int k[maxn];
    int i,j;
    int main()
    {
    	int n,x;
    	while(scanf("%d %d",&n,&x)!=EOF)
    	{
    		int ans = 0;
    		memset(vis, 0, sizeof(vis));
    		while(x)
    		{
    			vis[ans++] = x%2;
    			x /= 2;
    		}
    		memset(logo, 0, sizeof(logo));
    		memset(dis, 0, sizeof(dis));
    		memset(k, 0, sizeof(k));
    		for(i=0; i<n; i++)
    		{
    			scanf("%d",&a[i]);
    			int flag = a[i];
    			int d = 0;
    			while(flag)
    			{
    				dis[d++] = flag % 2;
    				flag /=2;
    				if(dis[d-1] && !vis[d-1])
    					logo[i] = 1;
    			}
    		}
    		int num = M;
    		for(i=0; i<n; i++)
    		{
    			if(logo[i])
    				continue;
    			int flag = a[i];
    			int d = 0;
    			while(flag)
    			{
    				k[d++] += flag%2;
    				flag /= 2;
    			}
    		}
    		for(i=0; i<ans; i++)
    		{
    			if(!vis[i])
    				continue;
    			num = min(k[i],num);
    		}
    		if(num == M)
    			printf("%d
    ",0);
    		else
    			printf("%d
    ",num);
    	} 
    	return 0;	
    } 
    

      

    这道题的思路不难,我的做法是利用or操作对位的影响。
    想一下,如果我们把几个二进制数or起来,我只要某一个数在某一位是1,那么结果的这一位就一定是1。
    下面举例说明解法:
    比如Y={1,2,4,8}     X=7
    即 Y:1,10,100,1000    X:111
    我们先排除掉那些把它们加入or式中一定会出现!=X的数字,这些数字满足(a|X)==X,也就是说如果一个数字,它的某一个位是1,而对应X的那一位是0,则无论这个数和谁相或,结果都一定不会等于X了。我们先从Y集合中去掉这些数,因为这些数恰恰是无论如何都不可能被去掉的,研究它们没有意义。这里去掉1000
    然后,统计X的每一个1位对应Y中是1的有几个:
    X:1    1     1
        100   10     1
    如果我们把Y改为{1,11,100}
    那么
    X:1           1        1       
        100       11     1、11
    我们要向使得任意子集相或都不为X,方法只有一个,那就是破坏掉X的一个1位,这样无论怎么组合都不会==X了,相反如果每一位都有数字保证,那么一定能组合出X。
    永远渴望,大智若愚(stay hungry, stay foolish)
  • 相关阅读:
    bzoj1966:[AHOI2005]病毒检测
    bzoj2938:[Poi2000]病毒
    bzoj3172:[Tjoi2013]单词
    luoguP3808[模板]AC自动机(简单版)
    luoguP3796[模板]AC自动机(加强版)
    Java 基本类型、封装类型、常量池、基本运算
    Java 内存分配(转)
    Java 数组ArrayList语法
    Java的修饰、继承、接口、抽象类
    2019数模国赛有感
  • 原文地址:https://www.cnblogs.com/h-hkai/p/7619971.html
Copyright © 2020-2023  润新知