题目传送门
卡常背包果然名不虚传
算法主体就是两种背包分开跑,先跑多重背包,再跑奇货
不知道为什么,这题二进制拆分好像要比单调队列优化快一些
然后这题毒瘤的地方就出来了:
如果一件物品的体积\(\times\)数量\(>\)背包体积,那么不用二进制拆分,当成完全背包来跑
快读一定要加
用自带的max函数也可能会T,最好手写\(if\)(这数据是得有多毒瘤)
真是一道很\((\tt{du})\)好\((\tt{liu})\)的背包题目啊
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline long long read(){
long long k=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') f=-1;
for(;c>='0'&&c<='9';c=getchar())
k=(k<<3)+(k<<1)+c-48;
return k*f;
}
long long dp[10010],v,w,cnt;
int main(){
#define int register int
int n=read(),m=read(),c=read();
for(int i=1;i<=n;i++){
int x=read(),y=read(),z=read();
if(x*z>c){
for(int j=x;j<=c;j++)
if(dp[j-x]+y>dp[j]) dp[j]=dp[j-x]+y;
}
for(int i=1,num=1;z;num=1<<i,i++){
if(z-num>=0){
z-=num,v=x*num,w=y*num;
for(int j=c;j>=v;j--)
if(dp[j-v]+w>dp[j]) dp[j]=dp[j-v]+w;
}
else{
v=x*z,w=y*z,z=0;
for(int j=c;j>=v;j--)
if(dp[j-v]+w>dp[j]) dp[j]=dp[j-v]+w;
}
}
}
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
for(int j=c;j>=0;j--)
for(int k=0;k<=j;k++)
if(dp[j-k]+x*k*k+y*k+z>dp[j])
dp[j]=dp[j-k]+x*k*k+y*k+z;
}
printf("%lld",dp[c]);
return 0;
}