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 }
  • 相关阅读:
    PAT (Advanced Level) Practice 1054 The Dominant Color (20 分)
    PAT (Advanced Level) Practice 1005 Spell It Right (20 分) (switch)
    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) (排序)
    hdu 5114 Collision
    hdu4365 Palindrome graph
    单链表查找最大值、两个递增的链表合并并且去重
    蓝桥杯-最短路 (SPFA算法学习)
    蓝桥杯-最大最小公倍数
    Codeforces-470 div2 C题
    蓝桥杯-地宫取宝
  • 原文地址:https://www.cnblogs.com/Ressed/p/9574848.html
Copyright © 2011-2022 走看看