0
点赞
收藏
分享

微信扫一扫

洛谷P3188 / HNOI2007 梦幻岛宝珠 题解

minute_5 2022-05-03 阅读 42

题面

原题链接

简要题解

这题就是一个大号01背包,所有的物品的体积均可以表示成 a × 2 b a \times 2^b a×2b
我们可以考虑对于每个不同的b, 设一个 d p dp dp F [ i ] [ j ] F[i][j] F[i][j], 处理出当 b = = i b == i b==i 时, Σ a \Sigma a Σa j j j 的最大价值,这一步相当于一个普通的 01 01 01 背包
考虑不同的 b b b 之间的转化:存在一个 b = = t b == t b==t, 考虑从 t − 1 t - 1 t1 t t t 的迭代, 我们设计一个 d p dp dp G [ i ] [ j ] G[i][j] G[i][j] , 表示当处理了 b ∈ [ 0 , i ] b \in [0, i] b[0,i] 时, 当 b = i b = i b=i Σ a = j \Sigma a = j Σa=j的最大价值, 即:
G [ i ] [ j ] = m a x ( F [ i ] [ j − k ] + G [ i − 1 ] [ m i n ( 10 × n , k × 2 + ( W > > ( i − 1 ) ) & 1 ) ] ) G[i][j] = max(F[i][j - k] + G[i - 1][min(10 \times n, k \times 2 + (W >> (i - 1)) \& 1)]) G[i][j]=max(F[i][jk]+G[i1][min(10×n,k×2+(W>>(i1))&1)])
此式子表示,当处理到 b = = i b == i b==i 时,在此位的 Σ a = j \Sigma a = j Σa=j,此时取出一些空间大小为 k k k 退位到低位来使用,再加上前 i − 1 i - 1 i1位所占有的空间 W > > ( i − 1 ) ) & 1 ) ] W >> (i - 1)) \& 1)] W>>(i1))&1)],而剩下的 j − k j - k jk, 就是在第 i i i 位进行使用,最优方案即为 F [ i ] [ j − k ] F[i][j - k] F[i][jk]

Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 33;
    const int M = 1222;
    long long F[N][M], G[N][M];
    long long w[N][M / 10], v[N][M / 10], num[N];
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define repd(i,a,b) for(int i=a;i>=b;i--)

    bool work(){
        int n, W;
        cin >> n >> W;
        memset(F, 0, sizeof(F));
        memset(G, 0, sizeof(G));
        memset(w, 0, sizeof(w));
        memset(v, 0, sizeof(v));
        memset(num, 0, sizeof(num));
        if(n == -1 && W == -1) return false;
        rep(i, 1, n){
            int x; cin >> x;
            int tmp = 31;
            while(x % (1ll << (--tmp)));
            w[tmp][++num[tmp]] = x / (1 << tmp);
            cin >> v[tmp][num[tmp]];
        }
        int m = 31;
        while(W <= (1 << (--m)));
        rep(i, 0, m){
            rep(j, 1, num[i]){
                repd(k, 10 * num[i], w[i][j]){
                    F[i][k] = max(F[i][k], F[i][k - w[i][j]] + v[i][j]);
                }
            }
        }
        rep(i, 0, 10 * num[0]) G[0][i] = F[0][i];
        rep(i, 1, m){
            rep(j, 0, 10 * n){
                rep(k, 0, j){
                    G[i][j]=max(G[i][j],F[i][j-k]+G[i-1][min(10*n,k*2+((W>>(i-1))&1))]);
                }
            }
        }
        cout<<G[m][1]<<endl;
        return true;
    }
    int main(){
        ios::sync_with_stdio(false);
        while(work());
    }
举报

相关推荐

0 条评论