解题思路:
题目就是求裸的多重背包。
朴素的多重背包是O(n3)O(n3),但用单调队列可以优化到O(n2)O(n2).
dp方程为:
f[j+k∗w[i]]=max(f[j+l∗w[i]]+(k−l)∗v[i])f[j+k∗w[i]]=max(f[j+l∗w[i]]+(k−l)∗v[i]),(0≤j<w[i],l>=k−cnt[i])(0≤j<w[i],l>=k−cnt[i])
即
f[j+k∗w[i]]=max(f[j+l∗w[i]]−l∗v[i]+k∗w[i])f[j+k∗w[i]]=max(f[j+l∗w[i]]−l∗v[i]+k∗w[i]),(0≤j<w[i],l>=k−cnt[i])(0≤j<w[i],l>=k−cnt[i])
用单调队列维护f[j+l∗w[i]]−l∗v[i]f[j+l∗w[i]]−l∗v[i]单减序列即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
//f[j+k*p]=max(f[j+q[head]*p]-q[head]*h+k*h)(q[head]>=k-c)
const int N=105;
int T,n,m,p,h,c,ans;
int f[N],tmp[N],q[N];
int main()
{
//freopen("lx.in","r",stdin);
T=getint();
while(T--)
{
memset(f,0,sizeof(f));
m=getint(),n=getint();
for(int i=1;i<=n;i++)
{
p=getint(),h=getint(),c=getint();
memcpy(tmp,f,sizeof(f));
memset(q,0,sizeof(q));
for(int j=0;j<p;j++)
{
int head=1,tail=0;
for(int k=0;j+k*p<=m;k++)
{
while(head<tail&&q[head]<k-c)head++;
while(head<=tail&&tmp[j+k*p]-k*h>tmp[j+q[tail]*p]-q[tail]*h)tail--;
q[++tail]=k;
f[j+k*p]=max(f[j+k*p],tmp[j+q[head]*p]+(k-q[head])*h);
}
}
}
ans=0;
for(int i=1;i<=m;i++)ans=max(ans,f[i]);
cout<<ans<<'\n';
}
}