题解 P1776 【宝物筛选_NOI导刊2010提高(02)】
Owen_codeisking · · 题解
引言
本蒟蒻在
多重背包与01背包和完全背包不一样的地方在于,它处于一个两者之间的境地,所以多重背包注定需要一些神奇的数据结构优化。
若你单调队列没学过,请你看一看
正文
首先声明,我的变量名与题中不一样。我定义
可知当
那么在已知
那么定义能放下的最大当前物品个数为
而
这一状态会被重复计算,这个时候单调队列就能排上用场了。
再定义
有且仅当在
那么我们理一下思路
(0)预处理时
(1)每次读进来一组
(2)逐一枚举
(3)在
#include <bits/stdc++.h>
#define maxn 110
#define maxm 100010
using namespace std;
int n,m;
int v[maxn],w[maxn],c[maxn];
int f[maxm],q[maxm];
int calc(int i,int u,int k){
return f[u+k*v[i]]-k*w[i];
}
int main()
{
memset(f,0xcf,sizeof(f));
scanf("%d%d",&n,&m);
f[0]=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&w[i],&v[i],&c[i]);
for(int u=0;u<v[i];u++){
int l=1,r=0;
int maxp=(m-u)/v[i];
for(int k=maxp-1;k>=max(maxp-c[i],0);k--){
while(l<=r&&calc(i,u,q[r])<=calc(i,u,k)) r--;
q[++r]=k;
}
for(int k=maxp;k>=0;k--){
while(l<=r&&q[l]>k-1) l++;
if(l<=r) f[u+k*v[i]]=max(f[u+k*v[i]],calc(i,u,q[l])+k*w[i]);
if(k-c[i]-1>=0){
while(l<=r&&calc(i,u,q[r])<=calc(i,u,k-c[i]-1)) r--;
q[++r]=k-c[i]-1;
}
}
}
}
int ans=0;
for(int i=1;i<=m;i++)
ans=max(f[i],ans);
printf("%d\n",ans);
return 0;
}
补充:正常