JZOJ 1756.得分

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值