• bzoj1492


    好题+神题,首先肯定是dp,我们设f[i]为到第i天能获得的最多的B卷(设获得的钱数亦可)
    由题目hint可知,要么全买要么全卖,我们有
    f[i]=max(maxmoney,f[j]*b[i]+f[j]*rate[j]*a[i]))/(a[i]*rate[i]+b[i]),
    这式子一看就是斜率优化,maxmoney可以先不管它
    考虑决策j,k不妨设j<k,如果决策k优于j那么有
    f[j]*b[i]+f[j]*rate[j]*a[i]<f[k]*b[i]+f[k]*rate[k]*a[i]
    可以得到(f[k]*rate[k]-f[j]*rate[j])/(f[k]-f[j])>-b[i]/a[i]
    我们设每个点是(f[k],f[k]*rate[k]),G(j,k)=(f[k]*rate[k]-f[j]*rate[j])/(f[k]-f[j])就是斜率
    很明显我们要维护一个上凸壳,但这里我们不能用单调队列,因为后面不是单调的
    可以用平衡树维护,但是我们观察这个式子
    后面状态不会对前面状态产生影响(修改独立),并且不强制在线
    于是我们可以用cdq分治来解决这个问题,我们还是根据天数顺序(状态)进行分治
    分治过程中关键就是算[l,mid]部分整体对后面[mid+1.r]部分的影响
    要能快速计算需要两个东西,首先我们要维护一个凸壳,
    其次我们要按照单调的顺序处理后面部分的-b[]/a[],这样我们可以用单调队列来做,
    我们可以先对-b[]/a[]降序排序(上凸线相邻两点间的斜率是递减的)
    然后先递归处理处于左边(状态时[l,mid])的点,
    在对一个区间都处理完毕之后,我们对这之间的点x为第一关键字排序,y为第二关键字排序
    这样我们就能得到就得到了[l,mid]这部分状态排好序的点,然后我们维护单调队列,算出[l,mid]整体对[mid+1,r]的影响
    然后我们再递归处理右边,完来之后再排序对[l,r]整体排序
    在处理排序的时候,很很明显我们可以用归并排序,这样每次递归时处理得复杂度都是O(L) L是区间长度
    所以根据主定理,T(n)=2T(n/2)+O(n) 复杂度是O(nlogn);
    注意这道题凸线会挂精度,到底在什么时候要保留精度呢?请求指教

      1 const eps=1e-9;
      2 type node=record
      3        a,b,ra,k,x,y:double;
      4        po:longint;
      5      end;
      6 
      7 var a,b:array[0..100010] of node;
      8     f:array[0..100010] of double;
      9     q:array[0..100010] of longint;
     10     i,n:longint;
     11 
     12 function getk(x,y:longint):double;
     13   begin
     14     if abs(a[y].x-a[x].x)<eps then exit(1e21);
     15     exit((a[y].y-a[x].y)/(a[y].x-a[x].x));
     16   end;
     17 
     18 function cmp(a,b:node):boolean;
     19   begin
     20     exit((a.x<b.x) or (abs(a.x-b.x)<eps) and (a.y<b.y));
     21   end;
     22 
     23 function max(a,b:double):double;
     24   begin
     25     if a>b then exit(a) else exit(b);
     26   end;
     27 
     28 procedure swap(var a,b:node);
     29   var c:node;
     30   begin
     31     c:=a;
     32     a:=b;
     33     b:=c;
     34   end;
     35 
     36 procedure sort(l,r:longint);
     37   var i,j:longint;
     38       x:double;
     39   begin
     40     i:=l;
     41     j:=r;
     42     x:=a[(l+r) shr 1].k;
     43     repeat
     44       while x<a[i].k do inc(i);
     45       while a[j].k<x do dec(j);
     46       if not(i>j) then
     47       begin
     48         swap(a[i],a[j]);
     49         inc(i);
     50         dec(j);
     51       end;
     52     until i>j;
     53     if l<j then sort(l,j);
     54     if i<r then sort(i,r);
     55   end;
     56 
     57 procedure cdq(l,r:longint);
     58   var m,i,l1,l2,t,j:longint;
     59   begin
     60     if l=r then
     61     begin
     62       f[l]:=max(f[l],f[l-1]);  //这里f[]代表的是钱数
     63       a[l].x:=f[l]/(a[l].ra*a[l].a+a[l].b);  //获得B券的数目
     64       a[l].y:=a[l].x*a[l].ra;
     65       exit;
     66     end;
     67     m:=(l+r) shr 1;
     68     l1:=l; l2:=m+1;
     69     for i:=l to r do  //先处理左部分的状态
     70       if a[i].po<=m then
     71       begin
     72         b[l1]:=a[i];
     73         inc(l1);
     74       end
     75       else begin
     76         b[l2]:=a[i];
     77         inc(l2);
     78       end;
     79     for i:=l to r do a[i]:=b[i];
     80     cdq(l,m);
     81 
     82     t:=0;
     83     for i:=l to m do
     84     begin
     85       while (t>1) and (getk(q[t-1],q[t])<getk(q[t-1],i)+eps) do dec(t);  //维护凸壳
     86       inc(t); q[t]:=i;
     87     end;
     88     j:=1;
     89     for i:=m+1 to r do
     90     begin
     91       while (j<t) and (getk(q[j],q[j+1])+eps>a[i].k) do inc(j); //计算影响(就是找第一个小于的斜率的左端点)
     92       f[a[i].po]:=max(f[a[i].po],a[q[j]].x*a[i].b+a[q[j]].y*a[i].a);
     93     end;
     94 
     95     cdq(m+1,r);
     96     l1:=l; l2:=m+1;
     97     for i:=l to r do  //归并排序
     98       if ((l2>r) or cmp(a[l1],a[l2])) and (l1<=m) then
     99       begin
    100         b[i]:=a[l1];
    101         inc(l1);
    102       end
    103       else begin
    104         b[i]:=a[l2];
    105         inc(l2);
    106       end;
    107 
    108     for i:=l to r do a[i]:=b[i];
    109   end;
    110 
    111 begin
    112   readln(n,f[0]);
    113   for i:=1 to n do
    114   begin
    115     readln(a[i].a,a[i].b,a[i].ra);
    116     a[i].k:=-a[i].b/a[i].a;
    117     a[i].po:=i;
    118   end;
    119   sort(1,n);
    120   cdq(1,n);
    121   writeln(f[n]:0:3);
    122 end.
    View Code
  • 相关阅读:
    hadoop2.2编程:MRUnit测试
    TestLinkConverter编程纪要
    Redisson的分布式锁的简单实现
    Jmeter工具使用
    JVM的学习(三)
    Mybatis需要注意的地方及知识点
    JVM学习二(JAVA的四种引用)
    mysql的引擎
    JVM学习一(JVM的内存结构和垃圾回收)
    JDk1.8HashMap的源码分析
  • 原文地址:https://www.cnblogs.com/phile/p/4472941.html
Copyright © 2020-2023  润新知