【bzoj4976】宝石镶嵌 乱搞+dp
2024-09-03 11:28:25
题目描述
从$n$个数中选出$n-k$个,使得它们的二进制或(or)最大。输出这个值。
输入
第一行包含两个正整数$n,k(2\le n\le 100000,1\le k\le 100,k<n)$,分别表示宝石的个数以及要扔掉的宝石个数。
第二行包含$n$个整数$w_1,w_2,...,w_n(0\le w_i\le 100000)$,分别表示每个宝石的魔力。
输出
输出一行一个整数,即最大的威力。
样例输入
4 1
32 16 8 7
样例输出
56
题解
乱搞+dp
由于上限为$100000$,因此最多只有$17$个二进制位。
考虑当可以保留的数的个数$n-k\ge 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\n" , 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\n" , i) , 0;
}
return 0;
}
最新文章
- Hibernate入门与简谈
- js 求时间差
- 【leetcode】Same Tree(easy)
- Codeforces Round #341 (Div. 2)
- c#面向对象基础 静态成员、构造函数、命名空间与类库
- sm30表维护做排序
- Android四大组件之——Activity的生命周期(图文详解)
- SpringServletContext简单案例
- 深入理解 KVC\KVO 实现机制 — KVC
- 简单高效读写修改整个文本Slurp
- 写了交互给后台后来不能用?bug多多多又找不到文件效率低?工作流程帮你优化起来~~~~
- Hadoop2.3.0具体安装过程
- linux command----vi
- vue添加页面键盘事件
- curl模拟访问已经存在的cookie
- Cdnbest的cdn程序默认支持web Socket
- java框架篇---hibernate之连接池
- Python爬虫——小说
- 使用Python3.x抓取58同城(南京站)的演出票的信息
- 003_Java笔记3:Eclipse添加jar包