1. 程式人生 > >[bzoj 1492][NOI2007]貨幣兌換Cash

[bzoj 1492][NOI2007]貨幣兌換Cash

傳送門

Solution

一道很早以前做過的題,突然想補篇部落格……

方程什麼的就不展現了。

反正斜率優化的題都挺好寫的。

斜率優化的核心是:
\[ \frac{Y_j-Y_k}{X_j-X_k}\leq W_i \]
可以把每個決策\(j\)用兩個數\(X_j\),\(Y_j\)來表示,然後如果\(X_j\)是個單增的呢,直接用單調棧就能維護凸殼(因為求凸殼的時候就要\(x-y\)排序一波啊),其實,我們不如說是在維護一個斜率的單調佇列,所以如果\(W_i\)和斜率的單調性相同,就可以直接用單調佇列找決策點啦。

\(W_i\)沒有單調性的話,就只能二分找決策點了。

比較頭疼的是要是\(X_i\)沒有單調性的話,我們就需要維護一個可以在中間加點的凸殼,平衡樹即可。

而cdq分治的思想就是分治區間,只考慮前面的決策對後面的詢問的影響,而順序是不需要考慮的,所以直接對前面的決策\(x-y\)排序求凸殼,對後面的詢問按照\(W_i\)排序,這樣一來,就又可以直接用單調佇列找決策點啦。


Code 

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define inf 0x7fffffff
#define MN 120000
#define sign(a) (((a)>-eps)-((a)<eps))
#define eps 1e-8
int n;
struct day{double A,B,rate;}a[MN];
double ans[MN],f[MN],g[MN];
int hd,tl,q[MN],krk[MN],rk[MN];
inline bool cmp(int x,int y){
    return f[x]<f[y]||(sign(f[x]-f[y])==0&&g[x]<g[y]);
}
inline double calc(int x,int y){
    if(sign(f[x]-f[y])==0) return (g[x]-g[y])*inf;
    return (g[x]-g[y])/(f[x]-f[y]);
}
inline bool cmpk(int x,int y){
    return sign((-a[x].A/a[x].B)-(-a[y].A/a[y].B))>0;
}
void solve_cdq(int l,int r){
    if(l==r){g[l]=f[l]/a[l].rate;return;}
    register int i,mid=(l+r)>>1;
    solve_cdq(l,mid);
    for(i=mid+1;i<=r;i++) rk[i]=i;sort(rk+l,rk+mid+1,cmp);
    for(i=mid+1;i<=r;i++) krk[i]=i;sort(krk+mid+1,krk+r+1,cmpk);
    tl=0,hd=1;
    for(i=l;i<=mid;i++){while(tl>1&&calc(q[tl-1],q[tl])<calc(q[tl],rk[i])) --tl;q[++tl]=rk[i];}
    for(i=mid+1;i<=r;i++){
        while(hd<tl&&sign(calc(q[hd],q[hd+1])-(-a[krk[i]].A/a[krk[i]].B))>=0)++hd;
        ans[krk[i]]=max(ans[krk[i]],f[q[hd]]*a[krk[i]].A+g[q[hd]]*a[krk[i]].B);
    }
    for(i=mid+1;i<=r;++i)
        ans[i]=max(ans[i],ans[i-1]),f[i]=ans[i]*a[i].rate/(a[i].A*a[i].rate+a[i].B);
    solve_cdq(mid+1,r);
}
int main(){
    register int i;
    n=read();scanf("%lf",&ans[1]);
    for(i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].A,&a[i].B,&a[i].rate),rk[i]=i;
    f[1]=ans[1]*a[1].rate/(a[1].A*a[1].rate+a[1].B);
    solve_cdq(1,n);
    printf("%.3f\n",ans[n]);
}



Blog來自PaperCloud,未經允許,請勿轉載,TKS!