[HEOI2013]Eden 的新背包问题
[HEOI2013]Eden 的新背包问题
题意:
多重背包,但是每一个询问会有一种物品不能选,询问最大价值。
分析:
首先进行二进制拆分是肯定的,但是这样直接算肯定不行。
我们回想起来原先 \(dp\) 状态的设定:
\(dp[i][j]\) 表示选到第 \(i\) 个物品,背包上限为 \(j\) 。
我们定义两个 \(dp\) 数组,一个表示选到第 \(i\) 个物品,另一个表示选到第 \(n-i\) 个物品。
计算答案时,就可以表示成 \(ans=max(dp[l][j]+dp[r+1][W-j])\)
其中,\(l\) 表示这个不能选择的物品最左端的位置 \(-1\) ,即为左侧最靠右能选择的物品。
\(r+1\) 则表示右侧最靠左能选择的物品。
分别进行计算之后就行了。
代码:
// P4095 [HEOI2013]Eden 的新背包问题
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
const int N=1e5+5;
int w[N],v[N],cnt,id[N];
ll f1[N][1005],f2[N][1005];
int main(){
cin>>n;
for(int i=1,x,y,z;i<=n;i++){
scanf("%d%d%d",&x,&y,&z); int now=1;
while(now<=z){
w[++cnt]=x*now,v[cnt]=y*now;
id[cnt]=i;
z-=now; now=now*2;
}
if(z){
w[++cnt]=x*z,v[cnt]=y*z; z=0;
id[cnt]=i;
}
}
for(int i=1;i<=cnt;i++){
for(int j=0;j<=1000;j++) f1[i][j]=f1[i-1][j];
for(int j=1000;j>=w[i];j--)
f1[i][j]=max(f1[i][j],f1[i-1][j-w[i]]+v[i]);
}
for(int i=cnt;i>=1;i--){
for(int j=0;j<=1000;j++) f2[i][j]=f2[i+1][j];
for(int j=1000;j>=w[i];j--)
f2[i][j]=max(f2[i][j],f2[i+1][j-w[i]]+v[i]);
}
cin>>m;
for(int i=1,now,W;i<=m;i++){
scanf("%d%d",&now,&W); now++;
ll ans=0; int l=0,r=0;
while(id[l+1]<now&&l<cnt) ++l; r=l;
while(id[r+1]<=now&&r<cnt) ++r;
for(int j=0;j<=W;j++) ans=max(ans,f1[l][j]+f2[r+1][W-j]);
cout<<ans<<endl;
}
system("pause");
return 0;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9