浅谈斜率优化

土地租用加强版

题目描述

随着YYHS的OI集训队人数急剧增加,原有的小机房已经容纳不了数量庞大的队员。
于是史老师决定租用一些实验室机位供队员们训练,他正在考虑为N (1 <= N <= 50,000)位队员租用机位。实验室管理员根据要求给出了N个机位的长和宽,每个机位的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000).
而机位的租用价格是它的面积,实验室管理员也提出,可以同时租用多个机位. 租用这一组机位的价格是它们最大的长乘以它们最大的宽, 但是机位的长宽不能交换. 如果想租下一个3x5的机位和一个5x3的机位,则他需要付5x5=25.
于是问题出现了,史老师希望租下所有的机位,但是他发现分组来租这些机位可以节省经费. 他需要你帮助他找到最小的经费.

输入

  • 第1行: 一个数: N
  • 第2..N+1行: 每行包含两个数,分别为机位的长和宽

输出

  • 第一行: 最小的可行费用.

样例输入

4
100 1
15 15
20 5
1 100

样例输出

500

提示

分3组租用这些机位: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15. 每组的价格分别为100,100,300, 总共500.
50:

var
  oo,i,j,k,n,m,maxi:longint;
  max:int64;
  a,b,f:array [1..1000000] of int64;
  function min(a,b:int64):int64;
  begin
    if a<b then exit(a)
    else exit(b);
  end;
  procedure qsort(l,r:longint);
  var
    i,j:longint;
    mid,t,mid1:int64;
  begin
    i:=l; j:=r;
    mid:=a[(l+r) div 2];
    mid1:=b[(l+r) div 2];
    while i<=j do
    begin
      while (a[i]<mid) or
            (a[i]=mid) and (b[i]<mid1) do inc(i);
      while (a[j]>mid) or
            (a[j]=mid) and (b[j]>mid1)do dec(j);
      if i<=j then
      begin
      t:=a[i];a[i]:=a[j];a[j]:=t;
      t:=b[i];b[i]:=b[j];b[j]:=t;
      inc(i); dec(j);
      end;
    end;
    if l<j then qsort(l,j);
    if i<r then qsort(i,r);
  end;
begin
  oo:=1000000000;
  readln(n);
  for i:=1 to n do read(a[i],b[i]);
  qsort(1,n);
  for i:=1 to n do
  begin
    f[i]:=oo;
    for j:=0 to i-1 do
    begin
      max:=0;
      maxi:=0;
      for k:=j+1 to i do
      begin
        if b[k]>max then begin max:=b[k];maxi:=k;end;
      end;
      f[i]:=min(f[i],f[j]+a[i]*b[maxi]);
    end;
  end;
    writeln(f[n]);
end.

100:

var
    n,u1,u2,gs,l,r:longint;
    a,b,q:array[0..50000]of longint;
    f:array[0..50000]of int64;
    procedure sweap(x,y:longint);
    var c:longint;
    begin
        c:=a[x];a[x]:=a[y];a[y]:=c;
        c:=b[x];b[x]:=b[y];b[y]:=c;
    end;
    procedure qsort(x,y:longint);
    var     
        l,r,f,k:longint;
    begin
        l:=x;r:=y;
        f:=a[(x+y)>>1];
        k:=b[(x+y)>>1];
        repeat
            while (a[l]<f) or ((a[l]=f) and (b[l]<k))do inc(l);
            while (a[r]>f) or ((a[r]=f) and (b[r]>k))do dec(r);
            if l<=r then 
            begin 
                sweap(l,r);
                inc(l);
                dec(r);
            end;
        until l>r;
        if l<y then qsort(l,y);
        if x<r then qsort(x,r);
    end;
    function slope(i,j:longint):real;
    begin 
        if b[j+1]=b[i+1] then 
            if f[i]>=f[j] then exit(maxlongint)
            else exit(-maxlongint);
        exit((f[i]-f[j])/(b[j+1]-b[i+1]));
    end;
begin
    readln(n);for u1:=1 to n do read(a[u1],b[u1]);
    qsort(1,n);
    for u1:=1 to n do 
    begin
        while(gs>0) and (a[gs]<=a[u1]) and (b[gs]<=b[u1]) do dec(gs);
        inc(gs);
        a[gs]:=a[u1];
        b[gs]:=b[u1];
    end;
    for u1:=1 to gs do 
    begin
        while (l<r) and (a[u1]>=slope(q[l],q[l+1])) do inc(l);
        f[u1]:=f[q[l]]+int64(a[u1])*b[q[l]+1];
        while (l<r) and (slope(q[r-1],q[r])>slope(q[r],u1))do dec(r);
        inc(r);q[r]:=u1;
    end;
    writeln(f[gs]);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值