zoukankan      html  css  js  c++  java
  • bzoj1492/luogu4027 货币兑换 (斜率优化+cdq分治)

    设f[i]是第i天能获得的最大钱数,那么

    f[i]=max{在第j天用f[j]的钱买,然后在第i天卖得到的钱,f[i-1]}

    然后解一解方程什么的,设$x[j]=frac{F[j]}{A[j]*Rate[j]+B[j]}$,$y[j]=Rate[j]*x[j]$的话,就能得到$f[i]=max{y[j]*A[i]+x[j]*B[i],f[i-1]}$

    然后再推一波斜率优化的式子,就可以得到,当j1比j2优时,$frac{y[j1]-y[j2]}{x[j1]-x[j2]}<-frac{B[i]}{A[i]}$

    然而$-frac{B[i]}{A[i]}$这玩意并不单调,所以需要用splay或者cdq分治维护一个斜率递减的凸包,来查询满足上式的斜率最大的那个点。

    然而懒得写splay了,所以用cdq分治来做(wa了几发以后才发现还不如去写splay呢写splay就不只是wa了

    我们来分治对所有点的询问。当然需要按照i从小到大来做。

    然后在做一个区间的时候,我是想用它的左子区间(保证这些的值已经求完了)去更新右子区间的值。

    也就是说,需要先做左子区间,然后做当前区间,最后再做右子区间(原理和寻找宝藏是一样的)

    做的时候,左边按x值排序,右边按$-frac{B[i]}{A[i]}$排序,然后给左半边用栈维护一个凸包,再用右半边的去扫,更新结果就行了。

    (别忘了f[i]可以等于f[i-1],具体做法是在l=r的时候更新一下)

    (常数好像写得很大..不管了.....)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<vector>
     6 #include<queue>
     7 #include<set>
     8 #include<ctime>
     9 #define LL long long
    10 using namespace std;
    11 const int maxn=100010;
    12 
    13 LL rd(){
    14     LL x=0;char c=getchar();int neg=1;
    15     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    16     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    17     return x*neg;
    18 }
    19 
    20 int N,stk[maxn],arr[maxn],tmp[maxn];
    21 double f[maxn],A[maxn],B[maxn],R[maxn];
    22 
    23 inline double gety(int i){return R[i]*f[i]/(A[i]*R[i]+B[i]);}
    24 inline double getx(int i){return f[i]/(A[i]*R[i]+B[i]);}
    25 inline double gett(int i){return -B[i]/A[i];}
    26 inline double getk(int i,int j){
    27     double dx=getx(i)-getx(j);if(fabs(dx)<=1e-9) dx=1e-9;
    28     return (gety(i)-gety(j))/dx;
    29 }
    30 inline bool cmpl(int a,int b){return getx(a)<getx(b);}
    31 inline bool cmpr(int a,int b){return gett(a)<gett(b);}
    32 
    33 void cdq(int l,int r){
    34     if(l>=r){f[arr[l]]=max(f[arr[l]],f[arr[l]-1]);return;}
    35     int m=l+r>>1,t=0;
    36     cdq(l,m);sort(arr+l,arr+m+1,cmpl);
    37     memcpy(tmp+m+1,arr+m+1,4*(r-m));sort(arr+m+1,arr+r+1,cmpr);
    38     for(int p=l;p<=m;p++){
    39         while(t>=2&&getk(stk[t],stk[t-1])<getk(stk[t],arr[p])) t--;
    40         stk[++t]=arr[p];
    41     }for(int q=m+1;q<=r;q++){
    42         while(t>=2&&getk(stk[t],stk[t-1])<gett(arr[q])) t--;
    43         int j=stk[t],i=arr[q];
    44         f[i]=max(f[i],gety(j)*A[i]+getx(j)*B[i]);
    45     }
    46     memcpy(arr+m+1,tmp+m+1,4*(r-m));cdq(m+1,r);
    47 }
    48 
    49 int main(){
    50     //freopen("testdata.in","r",stdin);
    51     //freopen(".out","w",stdout);
    52     int i,j,k;
    53     N=rd(),f[1]=rd();
    54     for(i=1;i<=N;i++){
    55         scanf("%lf%lf%lf",&A[i],&B[i],&R[i]);
    56         arr[i]=i;
    57     }cdq(1,N);
    58     double ans=0;
    59     for(i=1;i<=N;i++){
    60         ans=max(ans,f[i]);
    61     }printf("%.3lf
    ",ans);
    62     return 0;
    63 }
  • 相关阅读:
    oracle sql日期比较:
    vs 2008 过期问题
    silverlight带有复选框的列
    SQL 把一张表虚拟成两张表
    timeupdown
    ChildWindow 父窗体交互
    Debian CentOS修改时区
    如何优雅地使用命令行设置windows文件关联
    sql复制表结构,复制表内容语句
    VC6.0 中 添加/取消 块注释的Macro代码
  • 原文地址:https://www.cnblogs.com/Ressed/p/9574848.html
Copyright © 2011-2022 走看看