BZOJ 4976: 宝石镶嵌 背包
4976: 宝石镶嵌
Time Limit: 2 Sec Memory Limit: 128 MBDescription
魔法师小Q拥有n个宝石,每个宝石的魔力依次为w_1,w_2,...,w_n。他想把这些宝石镶嵌到自己的法杖上,来提升
法杖的威力。不幸的是,小Q的法杖上宝石镶嵌栏太少了,他必须扔掉k个宝石才能将剩下的宝石镶嵌上去。法杖的
威力等于镶嵌在上面的所有宝石的魔力按位做或(OR)运算的结果,请写一个程序帮助小Q做出最佳的选择,使得法
杖的威力最大。
Input
第一行包含两个正整数n,k(2<=n<=100000,1<=k<=100,k<n),分别表示宝石的个数以及要扔掉的宝石个数。
第二行包含n个整数w_1,w_2,...,w_n(0<=w_i<=100000),分别表示每个宝石的魔力。
Output
输出一行一个整数,即最大的威力。
Sample Input
4 1
32 16 8 7
32 16 8 7
Sample Output
56
题解:
当n - k >= 20 时, 我们0~20位二进制下都选一个为1的数,选满为20位就行了
当 n - k < 20, n和k都很小,暴力跑背包就可以了
#include <bits/stdc++.h> inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} using namespace std; int n, k, f[122][200000], a[200000]; int main() { cin >> n >> k; for(int i = 1; i <= n; ++i) cin>>a[i]; if(n - k >= 20) { int ans = 0; for(int j = 0; j < 20; ++j) for(int i = 1; i <= n; ++i) { if(((a[i]>>j)&1)) {ans |= a[i];break;} } cout << ans << endl; } else { for(int i = 0 ; i < 120; ++i) for(int j = 0; j < 200000; ++j) f[i][j] = 1000000000; f[0][0] = 0; for(int i = 0; i < n; ++i) { for(int j = 0; j < 200000; ++j) { if(j|a[i+1] < 200000) f[i+1][j|a[i+1]] = min(f[i+1][j|a[i+1]], f[i][j]+1); f[i+1][j] = min(f[i+1][j],f[i][j]); } } int ans = 0; for(int i = 0; i < 200000; ++i) if(f[n][i] <= n-k) ans = i; cout << ans << endl; } return 0; }