题目大意
n道题目,在第x分钟做对第i道题得Ai-Bi*x分,第i题一旦开始做就得连续的做Ci分钟。
给你m分钟,每道题目当然只能做一次,求最大得分。
偏序关系
如果我们已经决定了要做哪些题,如何分配最优顺序?
考虑对已知解得优化,假如做完第j道题后立刻做第k道题,交换这两题的做题顺序有没有可能更优?
不交换没有交换了优?那么
Aj−Bj∗Cj+Ak−Bk∗(Cj+Ck)<Ak−Bk∗Ck+Aj−Bj∗(Cj+Ck)
简化得
Bj/Cj<Bk/Ck
这是严格的偏序关系,而且具备传递性。
DP
按照偏序关系排序后,我们设f[i]表示选到第i题,然后可以枚举上一道做的题。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=3000+10;
int a[maxn],b[maxn],c[maxn],id[maxn],p[maxn],f[maxn][maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,ans,ca;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp(int j,int k){
return (ll)b[j]*c[k]<(ll)b[k]*c[j];
}
void calc(){
int i,j,k=0,t=0;
fo(i,1,n)
if (bz[i]) id[++k]=i;
fo(i,1,k-1)
fo(j,1,k-1)
if (cmp(id[j],id[j+1])) swap(id[j],id[j+1]);
i=0;
fo(j,1,k){
i+=c[id[j]];
t+=a[id[j]]-b[id[j]]*i;
}
ans=max(ans,t);
}
void dfs(int x,int y){
if (y>m) return;
if (x==n+1){
calc();
return;
}
bz[x]=1;
dfs(x+1,y+c[x]);
bz[x]=0;
dfs(x+1,y);
}
void work(){
ans=0;
fo(i,1,n) bz[i]=0;
dfs(1,0);
printf("%d\n",ans);
}
bool cmp2(int x,int y){
return (db)b[x]/c[x]>(db)b[y]/c[y];
}
int main(){
freopen("score.in","r",stdin);freopen("score.out","w",stdout);
ca=read();
while (ca--){
n=read();m=read();
fo(i,1,n) a[i]=read(),b[i]=read(),c[i]=read();
if (n<=10){
work();
continue;
}
fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmp2);
fo(i,1,n) p[i]=c[id[i]];
fo(i,1,n) c[i]=p[i];
fo(i,1,n) p[i]=b[id[i]];
fo(i,1,n) b[i]=p[i];
fo(i,1,n) p[i]=a[id[i]];
fo(i,1,n) a[i]=p[i];
fo(i,0,n)
fo(j,0,m)
f[i][j]=0;
ans=0;
fo(i,1,n)
fo(j,1,m){
f[i][j]=f[i-1][j];
if (j<c[i]) continue;
f[i][j]=max(f[i][j],f[i-1][j-c[i]]+a[i]-b[i]*j);
ans=max(ans,f[i][j]);
}
printf("%d\n",ans);
}
return 0;
}