题目大意:
题目链接:https://jzoj.net/senior/#main/show/100044
题目图片:
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7h522lqej30j50dk3zl.jpg
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7h522g0rj30jv0h3glu.jpg
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fy7h5226qpj30j204vgli.jpg
给定四个数组,求,使得
求。
思路:
看得出是一个多重背包吗?
对于第个“物品”:
- 价值
- 重量
- 个数
首先,由于必须选择至少个物品,所以就直接取走个物品。剩余个物品。
那么就是一个模板的多重背包了。
用二进制拆分变成背包,然后求出,最终答案就是必须选的部分。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=200010;
int n,m,s,a,b,c,d,ans,sum,w[N],v[N],f[N];
int main()
{
scanf("%d",&s);
while (s--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
sum+=a*d; //必须选
m-=a*c;
b-=a;
for (int i=1;i<=b;i*=2) //二进制拆分
{
w[++n]=i*c;
v[n]=i*d;
b-=i;
}
if(b) w[++n]=b*c,v[n]=b*d;
}
memset(f,0x80,sizeof(f));
f[0]=0;
for (int i=1;i<=n;i++) //背包
for (int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
printf("%d
",f[m]+sum);
return 0;
}