这道题思路很让人眼前一亮,
大致就是将前缀后缀的思维再套上多重背包。
设两个数组pre和suf ,
pre表示前i个数,权值不超过j下的最大价值。
suf表示从后往前,后i个数,权值不超过j下的最大价值。
这样,我要如果要任意去除第x位的物品的信息,就可以利用
max {pre[a-1][i]+suf[a+1][xx-i]} (xx指题目种给出的新的背包限制)
很快求出去除某一物品下的最大价值。
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define rep(x, y, z) for (int x = y; x <= z; x++)
#define dec(x, y, z) for (int x = y; x >= z; x--)
const int N = 1010, mod = 1e9 + 7;
const double expp = 1e-10;
typedef long long ll;
//------------------------
int n,m;
int pre[N][1100],suf[N][1100];
int v[N],w[N],s[N];
int main() {
cin>>n;
rep(i,1,n) {
cin>>v[i]>>w[i]>>s[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=1000;j++){
for(int k=0;k<=s[i];k++){
if(j-k*v[i]>=0)
pre[i][j] = max(pre[i][j],pre[i-1][j-k*v[i]]+k*w[i]);
}
}
}
for(int i=n;i>=1;i--){
for(int j=0;j<=1000;j++){
for(int k=0;k<=s[i];k++){
if(j-k*v[i]>=0)
suf[i][j] = max(suf[i][j],suf[i+1][j-k*v[i]]+k*w[i]);
}
}
}
int q; cin>>q;
while(q--){
int a,b; cin>>a>>b;
a ++ ;
int ans = 0;
for(int i=0;i<=b;i++)
ans = max(ans,pre[a-1][i]+suf[a+1][b-i]);
cout<<ans<<endl;
}
return 0;
}