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;
    }
    

     

  • 相关阅读:
    Spark 基本概念及入门
    Cron 表达式详解
    VmWare 网络模式
    微信、支付宝各种支付退款
    Spring Security OAuth2 SSO 单点登录
    Git 入门详解
    基于Spring Boot 2.x 的 Spring Cloud Admin 实践
    Git 提交规范
    Linux 安装 Mysql8.0
    Docker入门
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7677600.html
Copyright © 2011-2022 走看看