跪POPOQQQ神犇,一直在往容斥和2287的方向上想,虽然很明显不可行,其实只需要枚举左半边选多少右半边选多少就可以了,或者说的吊一点就是把左边看成一个泛化背包,右边看成一个泛化背包然后合并就好了。第一次写多重背包好激动呀!!!
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1010],b[1010];
int w[1010],v[1010],c[1010];
int f[1010][1010],g[1010][1010];
int n,m=1000,T,l,r;
void insert(int x,int y)
{
while (l<=r && b[r]<y) r--;
b[++r]=y;a[r]=x;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&c[i]);
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
{
if (c[i]*v[i]>m) c[i]=m/v[i];
for (int d=0;d<v[i];d++)
{
l=1,r=0;
for (int j=0;d+j*v[i]<=m;j++)
{
insert(j,f[i-1][d+j*v[i]]-j*w[i]);
if (j-a[l]>c[i]) l++;
f[i][d+j*v[i]]=b[l]+j*w[i];
}
}
}
memset(g,0,sizeof(g));
for (int i=n;i>=1;i--)
{
for (int d=0;d<v[i];d++)
{
l=1,r=0;
for (int j=0;d+j*v[i]<=m;j++)
{
insert(j,g[i+1][d+j*v[i]]-j*w[i]);
if (j-a[l]>c[i]) l++;
g[i][d+j*v[i]]=max(g[i+1][d+j*v[i]],b[l]+j*w[i]);
}
}
}
scanf("%d",&T);
while (T--)
{
int x,y;
scanf("%d%d",&x,&y);
x++;
int ans=0;
for (int i=0;i<=y;i++)
ans=max(ans,f[x-1][i]+g[x+1][y-i]);
printf("%d\n",ans);
}
return 0;
}