多重背包dp&&单调队列优化

点击查看代码
#include <bits/stdc++.h>
#define lowbit(x)(x&(-x))
using namespace std;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define int long long 
#define ld long double
#define __  cout<<"!"<<"\n"
#define ___ cout<<"?"<<"\n"
#define ____ cout<<"$"<<"\n"
#define _____ cout<<"@"<<"\n"
#define ls(x) tree[x].ls
#define rs(x) tree[x].rs
#define val(x) tree[x].val
#define mark(x) tree[x].mark
typedef pair<int,int> pairint;
const int MAXN=1e5+9;
const int N=1e5+9;
const int INF=(1e15);
const int mod=1e9+7;
/*char *p1,*p2,budp[100000];
int read()
{
    int x=0,f=1;char ch=nc();
    while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
    while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
   	return x*f;
}*/
int n,W;
int dp[MAXN];
struct NODE
{
    int pos,value;
}que[MAXN];
int c[MAXN],w[MAXN],num[MAXN];
void solve()
{
    cin>>n>>W;
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;++i)//枚举物品种类 
    {
        cin>>w[i]>>c[i]>>num[i];//c,w,num分别对应 体积,价值,个数 
        if(W/c[i] <num[i]) num[i]=W/c[i];//求lim
        for(int mo=0;mo<c[i];mo++)//枚举余数 
        {
            int head=0,tail=0;//队列初始化 
            for(int k=0;k<=(W-mo)/c[i];k++) 
            {
                int x=k;
                int y=dp[k*c[i]+mo]-k*w[i];
                while(head<tail && que[head].pos<k-num[i])head++;//限制长度
                while(head<tail && que[tail-1].value<=y)tail--;
                que[tail].value=y,que[tail].pos=x;
                tail++;
                dp[k*c[i]+mo]=que[head].value+k*w[i];
                //加上k*w[i]的原因:
                //我们的单调队列维护的是前i-1种的状态最大值.
                //因此这里加上k*w[i].
                //cout<<dp[k*c[i]+mo]<<"\n";
            }
        }
    }
    cout<<dp[W]<<"\n";
    return;
}

signed main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t=1;//cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

posted @ 2025-09-04 15:37  m_ooooooon  阅读(3)  评论(0)    收藏  举报