传送门
思路:
可以用 01 背包做,但是如果直接套用 01背包 模板就 GG 了。因为随着时间的推移,每个物品的价值在不断的发生改变。
现在考虑相邻的两个物品x,y。假设现在已经耗费 p 的时间,那么分别列出先做 x,y 的代价:
① a[ x ] - ( p + c[ x ] ) * b[ x ] + a[ y ] - ( p + c[ x ] + c[ y ] ) * by
② a[ y ] - ( p + c[ y ] ) * b[ y ] + a[ x ] - ( p + c[ y ] + c[ x ] ) * bx
对这两个式子化简,得到 ①>② 的条件是 c[ x ] * b[ y ] < c[ y ] * b[ x ]。
发现只要满足这个条件的物品对( x,y ),x 在 y 前的代价永远更优。
因此可以根据这个条件进行排序,之后就是简单的01背包了。
——参考 kkksc03
标程:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define maxn 51 typedef long long LL; LL T,n,ans=-0x3f; LL f[maxn][100001]; struct hh { LL ai,bi,ci; }t[maxn]; inline LL read() { LL kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } inline bool cmp(const hh&a,const hh&b) { return a.ci*b.bi<b.ci*a.bi; } int main() { T=read();n=read(); for(LL i=1;i<=n;i++) t[i].ai=read(); for(LL i=1;i<=n;i++) t[i].bi=read(); for(LL i=1;i<=n;i++) t[i].ci=read(); sort(t+1,t+n+1,cmp); for(LL i=1;i<=n;i++) { for(LL j=T;j>=0;j--) { if(t[i].ci<=j) { f[i][j]=max(f[i-1][j],f[i-1][j-t[i].ci]+t[i].ai-j*t[i].bi); } else f[i][j]=max(f[i][j],f[i-1][j]); } } for(LL i=1;i<=T;i++) ans=max(ans,f[n][i]); printf("%lld ",ans); return 0; }