SSL P2670 作业

71 篇文章 0 订阅
13 篇文章 0 订阅

题目大意:
老师给小A布置了n项作业,每一项作业都有截止时间di和价值vi(你可以理解成每做完一份作业就要快递过去给老师,且快递是不耗费时间的),每完成一项作业便可获得其价值。但小A发现,自己每一个单位时间内只能完成其中的一项作业,请你告诉小A,他最多可以获得多少价值。

【数据规模与约定】
对于前30%的数据,n<=100.
对于前60%的数据,n<=1000,di<=n
对于100%的数据,n<=100000,di,vi<=1000000000.

题解:
排序+堆维护:

我们先对时间排序从小到大,快排、归排什么的都可以,冒泡,选排的话..

然后我们去维护一个小根堆
每次加入枚举到的一个i
di ≤ M 则看vi能否替换掉其堆顶,可以则替换然后维护
di > M 则将vi放到堆底,然后上移维护

M为堆内数的个数

最后这个小根堆里的值的总和就是最大价值

时间复杂度:O(N log N+M*log N)

var
    d,v:array [0..100001] of longint;
    rp:array [0..200001] of longint;
    i,j,n,m:longint;
    ans:int64;

procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    if l>=r then exit;
    i:=l; j:=r;
    mid:=d[(l+r) div 2];
    repeat
         while d[i]<mid do inc(i);
         while d[j]>mid do dec(j);
         if i<=j then
            begin
                d[0]:=d[i];d[i]:=d[j];d[j]:=d[0];
                v[0]:=v[i];v[i]:=v[j];v[j]:=v[0];
                inc(i); dec(j);
            end;
    until i>j;
    qsort(i,r);
    qsort(l,j);
end;

procedure up(x:longint);
begin
    if x=1 then exit;
    repeat
      if rp[x]<rp[x div 2]
        then begin
                rp[0]:=rp[x];
                rp[x]:=rp[x div 2];
                rp[x div 2]:=rp[0];
             end
        else break;
      x:=x div 2;
    until x=0;
end;

procedure down(x:longint);
begin
    if 2*x>m then exit;
    repeat
       x:=2*x;
       if x+1<=m then
          if rp[x]>rp[x+1] then inc(x);
       if rp[x div 2]>rp[x] then
          begin
               rp[0]:=rp[x];
               rp[x]:=rp[x div 2];
               rp[x div 2]:=rp[0];
          end
        else break;
  until 2*x>m;
end;

begin
    readln(n);
    for i:=1 to n do
      readln(d[i],v[i]);

    qsort(1,n);

    m:=0;
    for i:=1 to n do
      begin
           if d[i]<=m
           then begin
                     if v[i]>rp[1] then
                     begin
                            rp[1]:=v[i];
                            down(1);
                     end
                end
           else begin
                     inc(m);
                     rp[m]:=v[i];
                     up(m);
                end;
      end;

    ans:=0;

    for i:=1 to m do
      ans:=ans+rp[i];

    writeln(ans);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值