BZOJ 4976: 宝石镶嵌 背包

4976: 宝石镶嵌

Time Limit: 2 Sec  Memory Limit: 128 MB

Description

魔法师小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

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

 

posted @ 2017-09-05 18:58  meekyan  阅读(275)  评论(0编辑  收藏  举报