zoukankan      html  css  js  c++  java
  • bzoj 1492

    这道题真好。。。

    首先,感觉像DP,但是如果按照原题意,有无数个状态,每个状态又有无数个转移。

    然后思考,我们每次买一部分和卖一部分的原因是什么,如果没有那个比例(就是rate=1恒成立),那么很容易贪心证明每次必须买完或卖完,但加了比例后就没那么好证明了,感觉一下吧。

    然后就可以写DP方程了(dp[i]表示通过前i天的交易,到达第i天时,身上最多的钱)

    clip_image002

    (内层的max前面那项很好解决主要是后面的那个转移,所以后面就之考虑后面那个)

    这个转移中有i的信息与j的信息相乘的项,所以考虑是否可用斜率优化,设有两项:k<j<i,那么“选j比选k优”当且仅当:

    clip_image004

    我们化简:

    clip_image006

    设:

    clip_image008

    clip_image010

    那么就是:

    clip_image012

    走到这我们就走不动了,因为f或g函数没有单调性,我们就没办法像普通的斜率优化那样除过去。这时我们回过头,发现我们设的k<j<i没有什么用,对上面那个式子的化简没有什么用,想想后,恍然大悟,我们以前斜率优化的时候,之所以设k<j<i是因为上面的f函数或g函数是单调的,我们设了k<j<i的目的主要是为了让g[j]-g[k]或f[j]-f[k]的正负恒定,这样就可以除过去了,这道题,我们不妨不设k<j<i,而直接设j<i,k<i,且g[j]>g[k](当然也可以设g[j]<g[k],f[i]>f[k]或f[i]<f[k]),这样上面那个式子就可以化简了:

    clip_image014

    是不是很像斜率优化,和斜率优化一样,我们把每个决策点j看成是一个点:(g[j],f[j]),容易证明,最优决策点一定是上凸壳上的一个点:

    clip_image016

    以上图为例子,当前计算的状态是i(其对应斜率-b[i]/a[i]为绿线的斜率),后很多决策点(红点),上凸壳上的点已经标号。此时最有决策点是B,最优决策点的左右两条直线的斜率把当前状态的斜率卡在中间。

    这道题和普通的斜率优化不同的地方在于,普通的斜率优化的状态的斜率是单调的(即绿线的斜率),并且每个状态作为决策点的横坐标也是单调的(即每次新加入的蓝点的横坐标是单调的),这就让我们可以均摊O(1)地插入一个点到凸包并且O(1)地找到我们的最优决策点。

    但这道题就不行,上面两个性质它都不满足,所以一般的思路是用平衡树维护一个上凸壳,这样插入一个决策点和找一个最有决策点的复杂度都是O(logn)的,可以搞定这道题,但我没写过动态维护凸壳,听说难写难调。

    然后这道题就成了时间分治(cdq分治?)的例题。

    时间分治是这样的:对于一个序列:

    ABABAABBBABABABABABABAAB

    其中B是一个询问,其答案取决于其前面的A,并且A对B的影响独立(即可以用单个A就可以更新B,只要前面的A都更新过B,那么B的答案就是正确的)。那么就可以时间分治了。对于上面那个序列,我们先拆成两半:

    1、ABABAABBBABA

    2、BABABABABAAB

    我们解决了1、2两个子问题后,合并时只要把1中的A对2中的B的影响更新到B,那么就可以了。

    ABABAABBBABA BABABABABAAB

    即只要用红色的A去更新蓝色的B,那么当前的任务就完成了,将有颜色的部分提出来,我们发现A全在B前面,就是说我们只需解决“先给出所有A,再给出所有B”这个问题就可以了。(这个就提供给我们了一个将ABABAB问题并且满足上面那个影响独立性质的问题以一个log的复杂度变成AAABBB问题)

    至于这道题,我们的A是给出一个点,我们的B是前面的所有点选一个最优决策点来更新B,因为只要我们把可能最优的A去更新B,那么B就一定会得到最优答案,所以满足“影响独立”原则,这道题有个细节要注意,就是我们的A和B是合在一起的,并且只有知道了B的答案,才知道A,也就是说我们每次分治时,要先解决左边的子问题,然后用左边的决策点去更新右边的询问点,在解决右边的子问题。

    感谢xhr和cdq的论文。

      1 /**************************************************************
      2     Problem: 1492
      3     User: idy002
      4     Language: C++
      5     Result: Accepted
      6     Time:1564 ms
      7     Memory:11508 kb
      8 ****************************************************************/
      9  
     10 /*
     11     dp[1] = s
     12     dp[i] = max{ dp[i], dp[j]*(a[i]*r[j]+b[i])/(a[j]*r[j]+b[j]) | j in [1,i) } i in [2,n]
     13  
     14     f[i] = (dp[i]*r[i])/(a[i]*r[i]+b[i])
     15     g[i] = dp[i]/(a[i]*r[i]+b[i])
     16     dp[i] = max{ dp[i], f[j]*a[i]+g[j]*b[i] | j in [1,i) } i in [2,n]
     17     ( g[i], f[i] ) as point
     18     k[i] = -b[i]/a[i]
     19 */
     20 #include <cstdio>
     21 #include <cmath>
     22 #include <iostream>
     23 #include <vector>
     24 #include <algorithm>
     25 #define N 100010
     26 #define eps 1e-10
     27 #define fprintf(...)
     28 using namespace std;
     29  
     30 int sg( double x ) { return (x>-eps)-(x<eps); }
     31 struct Vector {
     32     double x, y;
     33     Vector(){}
     34     Vector( double x, double y ):x(x),y(y){}
     35     Vector operator+( const Vector &b ) const { return Vector(x+b.x,y+b.y); }
     36     Vector operator-( const Vector &b ) const { return Vector(x-b.x,y-b.y); }
     37     Vector operator*( double b ) const { return Vector(x*b,y*b); }
     38     Vector operator/( double b ) const { return Vector(x/b,y/b); }
     39     double operator^( const Vector &b ) const { return x*b.y-y*b.x; }
     40     double operator&( const Vector &b ) const { return x*b.x+y*b.y; }
     41     double ang() { return atan2(y,x); }
     42     bool operator<( const Vector &b ) const { return x<b.x||(x==b.x&&y<b.y); }
     43 };
     44 typedef Vector Point;
     45  
     46 int n; 
     47 double s;
     48 double aa[N], bb[N], rr[N], kk[N]; 
     49 double f[N], g[N], dp[N];
     50 double ag[N];
     51  
     52 bool onleft( Point &a, Point &b, Point &c ) {
     53     return sg( (b-a)^(c-a) ) > 0;
     54 }
     55 void convex( vector<Point> &p, vector<Point> &c ) { //  up convex
     56     sort( p.begin(), p.end() );
     57     c.push_back( p.back() );
     58     for( int i=p.size()-2; i>=0; i-- ) {
     59         while( c.size()>1 && !onleft( c[c.size()-2], c[c.size()-1], p[i] ) ) 
     60             c.pop_back();
     61         c.push_back( p[i] );
     62     }
     63 }
     64 bool cmp_k( int a, int b ) {
     65     return kk[a]>kk[b];
     66 }
     67 void cdq( int lf, int rg, vector<Point> &c ) {
     68     if( lf==rg ) {
     69         int i=lf;
     70         dp[i] = max( dp[i], s );
     71         s = max( dp[i], s );
     72         g[i] = dp[i]/(aa[i]*rr[i]+bb[i]);
     73         f[i] = rr[i]*g[i];
     74         c.push_back( Point(g[i],f[i]) );
     75 //      fprintf( stderr, "dp[%d] = %lf (%.2lf,%.2lf) %.2lf
    ", i, dp[i], g[i], f[i], kk[i] );
     76 //      fprintf( stderr, "i=%d dp=%.2lf f=%.2lf g=%.2lf
    ",
     77 //              i, dp[i], f[i], g[i] );
     78         return;
     79     }
     80     int mid=(lf+rg)>>1;
     81     vector<Point> cl, cr;
     82     vector<int> vr;
     83     cdq( lf, mid, cl );
     84     for( int i=0; i<cl.size()-1; i++ ) {
     85         Vector u = cl[i+1]-cl[i];
     86         if( sg(u.x)==0 ) {
     87             if( u.y>0.0 )
     88                 ag[i] = 1e20;
     89             else
     90                 ag[i] = -1e20;
     91         } else
     92             ag[i] = u.y/u.x;
     93     }
     94     for( int i=mid+1; i<=rg; i++ )
     95         vr.push_back( i );
     96     sort( vr.begin(), vr.end(), cmp_k );
     97     for( int i=0,j=0; j<vr.size(); j++ ) {
     98         int k=vr[j];
     99         while( i<cl.size()-1 && ag[i]>kk[k] ) i++;
    100         dp[k] = max( dp[k], cl[i].x*bb[k]+cl[i].y*aa[k] );
    101     }
    102     cdq( mid+1, rg, cr );
    103     for( int i=0; i<cr.size(); i++ )
    104         cl.push_back( cr[i] );
    105     convex( cl, c );
    106     reverse( c.begin(), c.end() );
    107 }
    108 int main() {
    109     scanf( "%d%lf", &n, &s );
    110     for( int i=1; i<=n; i++ ) {
    111         scanf( "%lf%lf%lf", aa+i, bb+i, rr+i );
    112         kk[i] = -bb[i]/aa[i];
    113     }
    114     vector<Point> c;
    115     cdq(1,n,c);
    116     double ans = 0.0;
    117     for( int i=1; i<=n; i++ )
    118         ans = max( ans, dp[i] );
    119     printf( "%.3lf
    ", ans );
    120 }
    121  
    122 
    View Code
  • 相关阅读:
    leetcode 13. Roman to Integer
    python 判断是否为有效域名
    leetcode 169. Majority Element
    leetcode 733. Flood Fill
    最大信息系数——检测变量之间非线性相关性
    leetcode 453. Minimum Moves to Equal Array Elements
    leetcode 492. Construct the Rectangle
    leetcode 598. Range Addition II
    leetcode 349. Intersection of Two Arrays
    leetcode 171. Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/idy002/p/4457450.html
Copyright © 2011-2022 走看看