梦幻岛宝珠 个人题解

发布时间 2023-08-03 10:24:12作者: 552Hz

这题的物品数量非常小,但是背包的重量非常大,我们采用压缩到二进制位来考虑,因为最多是n*20的数位*个数,并且上一位dp的状态不影响下一位。所以我们设计当前dp的状态为选取了前i位置时候所能获得的最大值。又因为上一维在数组dp时可能会被上一维的影响所以f[min(2*i+d,s)] =max(f[min(2*i+d,s)],g[i]);来在这一维中更新当前的值。最后再在vector里面跑一下当前维数的背包,最后f[0]就是背包剩余容量为0时的体积

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
const ll inf=1ll<<60;
vector<pair<int,int>>item[40];
ll f[2010],g[2010];
int n,W;
void solve(){
    int s=0;
    for(int i=0;i<=30;i++){
        item[i].clear();
    }
    for(int i=0;i<n;i++){
        int w,v;
        cin>>w>>v;
        int lev=__builtin_ctz(w);
        w>>=lev;
        item[lev].push_back({w,v});
        s+=w;
    }
    for(int i=0;i<=s;i++)f[i]=-inf;
    f[0]=0;
    for(int i=30;i>=0;i--){

        for(int i=0;i<=s;i++) g[i]=f[i],f[i]=-inf;
        int d=(W>>i)&1;
        for(int i=0;i<=s;i++){
            f[min(2*i+d,s)] =max(f[min(2*i+d,s)],g[i]);
        }

        for(int i=s-1;i>=0;i--)
            f[i] =max(f[i],f[i+1]);

        for(auto p:item[i]) {
            for(int i=p.first;i<=s;i++){
                f[i-p.first] =max(f[i-p.first],f[i]+p.second);
            }
        }
    }
    cout<<f[0]<<endl;
}


int main() 
{
    std::ios::sync_with_stdio(false);
    cin.tie(0); 
    cout.tie(0);
    while(true){
        cin>>n>>W;
        if(n==-1||W==-1){
            break;
        }
        solve();
    }
    return 0;
}

个人题解,如有错误欢迎指正