zoukankan      html  css  js  c++  java
  • 【bzoj4976】宝石镶嵌 乱搞+dp

    题目描述

    从$n$个数中选出$n-k$个,使得它们的二进制或(or)最大。输出这个值。

    输入

    第一行包含两个正整数$n,k(2le nle 100000,1le kle 100,k<n)$,分别表示宝石的个数以及要扔掉的宝石个数。
    第二行包含$n$个整数$w_1,w_2,...,w_n(0le w_ile 100000)$,分别表示每个宝石的魔力。

    输出

    输出一行一个整数,即最大的威力。

    样例输入

    4 1
    32 16 8 7

    样例输出

    56


    题解

    乱搞+dp

    由于上限为$100000$,因此最多只有$17$个二进制位。

    考虑当可以保留的数的个数$n-kge 17$时,显然对于每一位选出一个该位为$1$的数,选出来的数一定不超过$17$个。因此一定能够占满所有的二进制位。所以所有的数的二进制或即为答案。

    当$n-k<17$时,由于$k$只有$100$,所以$n$只有$117$,因此可以暴力dp。设$f[i][j]$表示能否选出$i$个数使得它们的二进制或为$j$。然后随便转移即可。

    时间复杂度$O(117*17*2^{17})$。

    #include <cstdio>
    bool f[17][131080];
    int main()
    {
    	int n , m , i , x , ans;
    	scanf("%d%d" , &n , &m);
    	if(n - m >= 17)
    	{
    		ans = 0;
    		for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , ans |= x;
    		printf("%d
    " , ans);
    	}
    	else
    	{
    		f[0][0] = 1;
    		int j , k;
    		for(i = 1 ; i <= n ; i ++ )
    		{
    			scanf("%d" , &x);
    			for(j = 0 ; j < n - m ; j ++ )
    				for(k = 0 ; k < 131072 ; k ++ )
    					f[j + 1][k | x] |= f[j][k];
    		}
    		for(i = 131071 ; ~i ; i -- )
    			if(f[n - m][i])
    				return printf("%d
    " , i) , 0;
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    判断两个数组是否相等
    IIS应用程序池性能分析
    配置Windows Update,补丁更新
    正则表达式从右往左进行匹配(Regex)
    OpenSSL
    openssl用法详解
    OpenSSL生成公钥私钥***
    HTTP认证与https简介
    单机至亿级流量大型网站系统架构的演进过程
    程序员常用英语词汇
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7677600.html
Copyright © 2011-2022 走看看