题目链接
算法的详细证明在这
单调队列适用于求一定区间长度情况下,所有区间的最值。
#include<bits/stdc++.h>
using namespace std;
const int N =20010;
int n,m,v,w,s,f[N];
int q[N],num[N];//q:队列,num:保存队列中元素所在的位置,方便维护区间长度
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&v,&w,&s);
for(int j=0;j<v;j++)//枚举余数
{
int l=0,r=-1;//单调队列头和尾
for(int k=0;k<=(m-j)/v;k++)//所选物品体积x=j+k*v,枚举所有的k
{
int tmp=f[k*v+j]-k*w;//先减最后再加
if(l<=r&&num[l]<k-s) l++;//弹出不在区间的队头
while(l<=r&&q[r]<=tmp) r--;//弹出破坏单调性的队尾
num[++r]=k;//入队
q[r]=tmp;
f[k*v+j]=q[l]+k*w;//队头即为最大值
}
}
}
cout<<f[m]<<endl;
return 0;
}