Jzoj4892 最优得分
给你n道题目,你有t的时间,每个题有一个初始的分数Ai,让后每过1分钟,第i道题目分值减少Bi
假设你可以做出全部题目,而做一个题i的用时是固定的常数Ci,那么请问你最多能得到多少分
(好刺激的赛制呢)
显然是一个dp,但是光dp还不够,我们还要套上贪心才能最优
考虑当前已经决定做哪几道题目,那么用什么顺序去完成这些题目得分最高?
我们随便考虑一个顺序X,考虑交换其中两个题目X[j]和X[j+1]
如果保持不变,那么损失C[x[i]]*B[x[i+1]]分,如果交换,则损失B[x[i]]*C[x[i+1]]分
比较两者大小,若C[x[i]]*B[x[i+1]]>B[x[i]]*C[x[i+1]]则应该交换两者
移项可得B[x[i]+1]/C[x[i]+1]>B[x[i]]/C[x[i]]
所以我们将所有的题目按照B[i]/C[i]从大到小排序
让后做类似于01背包问题的dp即可
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct Q{ int A,B,C; } s[1010];
int f[3010],n,m;
inline bool c1(Q a,Q b){ return a.C*b.B>b.C*a.B; }
int score(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d%d%d",&s[i].A,&s[i].B,&s[i].C);
memset(f,0,3010<<2);
sort(s+1,s+1+n,c1);
for(int i=1;i<=n;++i)
for(int j=m;j>=s[i].C;--j)
f[j]=max(f[j],f[j-s[i].C]+s[i].A-(m-j+s[i].C)*s[i].B);
printf("%d\n",f[m]);
}
int main(){
freopen("score.in","r",stdin);
freopen("score.out","w",stdout);
int T; for(scanf("%d",&T);T--;score());
}