Description
现在yk手上有N道题,他总共有T的时间来完成他们中的一些或全部。每道题有一个完成所需时间t[i]和一个难度系数c[i]。如果yk在剩余x个单位时间的时候开始做题i,并且能够完成,那么总分加上x*c[i]。现在yk要从这N道题中选出一些在T个单位时间内完成,并且按照某种顺序依次完成它们(yk每个单位时间只能做一道题,并且一旦他决定做某题就会一直做直到做完),那么他最多能够拿到多少分呢?
Input
第一行,两个用空格隔开的正整数N和T,分别表示题目总数和总时间。
第2到N+1行,每行包含两个正整数,第i+1行的两个正整数分别表示t[i]和c[i]
Output
一行一个整数,表示最大能够得到的分数
Sample Input Output
输入1:
3 10
2 1
8 9
2 5
输出1:
122
Hint
最优方案为在剩余10个单位时间的时候开始做第3题(需要2个单位时间),剩余8个单位时间的时候开始做第2题(需要8个单位时间),总得分为10×5+(10-2)×9=122。
输入2:
3 12
3 6
7 5
4 2
输出2:
117
Data Constraint
对于20%的数据,N≤8,T≤200。
对于40%的数据,N≤15,T≤1000。
对于另外30%的数据,N≤2000且满足T不小于做完N道题所需时间的总和。
对于全部的数据,N≤3000,T≤10000,所有的ti和ci均不超过100。
Solution
证明选择顺序的结论
首先我们按照C[i]/T[i]从大到小排一个序,因为先选择前面的题是较优的。
证明过程:
假如有i,j (i<j),c[i]/t[i]>c[j]/t[j],则有C[i]T[j]>C[j]T[i]。
假设剩余x分钟,剩余i,j两道题未选,则先选i是较优的。
我们可以将表示先选i和先选j获得的得分的式子列出来:
先选i,则价值为x* C[i]+(X-T[i])*C[j] 拆开后得到 xC[i]+xC[j]-C[j]T[i]
先选j,则价值为x* C[j]+(X-T[j])*C[i] 拆开后得到 xC[i]+xC[j]-C[i]T[j]
∵C[i]T[j]>C[j]T[i]
∴-C[i]T[j]<-C[j]T[i]
∴先选i的价值比先选j的得分多。
∴以先选i是较优的
接下来我们打背包。设F[j]为**剩余**j分钟,所得得分的最大值,则选完前i-1题的最高得分为F[j+t[i]],得分则为(j+t[i]-1)*C[i],答案就是f[j]的最大值。
Code
var f:array[0..10000] of longint;
v,w:array[0..3001] of longint;
g:array[0..3001] of extended;
i,j,k,l,n,m,t,ans:longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure qsort(l,r:longint);
var i,j:longint;
mid:extended;
begin
i:=l;
j:=r;
mid:=g[(l+r)div 2];
repeat
while (g[i]>mid) do inc(i);
while (g[j]<mid) do dec(j);
if i<=j then
begin
w[0]:=w[i];w[i]:=w[j];w[j]:=w[0];
v[0]:=v[i];v[i]:=v[j];v[j]:=v[0];
g[0]:=g[i];g[i]:=g[j];g[j]:=g[0];
inc(i);dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
readln(n,t);
fillchar(f,sizeof(f),128);
f[t+1]:=0;
for i:=1 to n do
begin
readln(v[i],w[i]);
g[i]:=w[i]/v[i];
end;
qsort(1,n);
for i:=1 to n do
begin
for l:=1 to t do
begin
f[l]:=max(f[l],f[l+v[i]]+(l+v[i]-1)*w[i]);
if f[l]>ans then ans:=f[l];
end;
end;
writeln(ans);
end.
——2016.2.18