貨幣兌換 [Noi2007 ,Codevs 1797]

題目地址請點擊——


貨幣兌換


這裏寫圖片描述


Solution

f(x) 表示第 x 天最多獲得的金錢,則方程爲:

f(1)=s,f(i)=max(maxi1j=1f(j)riai+biajrj+bj,f(i1))

移項,化簡得到斜率公式:
a(i)b(i)[A(j)r(j)A(k)r(k)]>[A(k)A(j)]

其中 A(x)=f(x)/(ajrj+bj)
可以用斜率優化,但因爲 a(i)b(i)A(i)r(i) 均不單調,所以要用cdq分治

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

#define Max(x,y) ((x)>(y)?(x):(y))
#define eps (1e-8)
#define MAXN 100010
#define INF 1e+10

using namespace std;

struct Day{double a,b,r,x,y,A;int num;}day[MAXN],t[MAXN];
struct KKK{double ks;int num;}stack[MAXN];
double f[MAXN];
int n,s,Max_Right,limit=sizeof(Day),Lastcost;

inline int compare(double x){
    if(fabs(x)<=eps)return 0;
    return x>0?1:-1;
}

bool cmp(Day x,Day y){
    if(fabs(x.a/x.b-y.a/y.b)<=eps||x.a/x.b-y.a/y.b<0)return true;
    return false;
}

double get_k(int x,int y){
    if(day[x].x==day[y].x)return INF;
    return (day[x].y-day[y].y)/(day[x].x-day[y].x);
}

void solve(int l,int r){
    if(l==r){
        f[day[l].num]=Max(f[day[l].num],f[day[l].num-1]);
        day[l].A=f[day[l].num]/(day[l].a*day[l].r+day[l].b);
        day[l].x=day[l].A*day[l].r,day[l].y=-day[l].A;
    }
    else{
        int mid=(l+r)>>1,fir=l,sec=mid+1;
        for(int i=l;i<=r;i++){
            if(day[i].num<=mid)t[fir++]=day[i];
            else t[sec++]=day[i];
        }
        for(int i=l;i<=r;i++)day[i]=t[i];
        solve(l,mid);Max_Right=Lastcost=1;
        stack[Max_Right].num=l;stack[Max_Right].ks=-INF;
        for(int i=l+1;i<=mid;i++){
            while(compare(get_k(stack[Max_Right].num,i)-stack[Max_Right].ks)<=0)Max_Right--;
            stack[++Max_Right].num=i;stack[Max_Right].ks=get_k(stack[Max_Right-1].num,i);
        }
        stack[Max_Right+1].ks=INF;
        for(int i=mid+1;i<=r;i++){
            double tmp=day[i].a/day[i].b;
            while((compare(stack[Lastcost].ks-tmp)>0||compare(stack[Lastcost+1].ks-tmp)<0)&&Lastcost<Max_Right)Lastcost++;
            int pos=day[stack[Lastcost].num].num,real=day[i].num;
            f[real]=Max(f[real],f[pos]*(day[stack[Lastcost].num].r*day[i].a+day[i].b)/(day[stack[Lastcost].num].a*day[stack[Lastcost].num].r+day[stack[Lastcost].num].b));
        }
        solve(mid+1,r);
        fir=l,sec=mid+1;
        for(int i=l;i<=r;i++){
            if(fir>mid)t[i]=day[sec++];
            else if(sec>r)t[i]=day[fir++];
            else{
                double tx=day[fir].x,ty=day[sec].x;
                if(compare(tx-ty)<=0)t[i]=day[fir++];
                else t[i]=day[sec++];
            }
        }
        for(int i=l;i<=r;i++)day[i]=t[i];
    }
}

int main(){

    freopen("cash.in","r",stdin);
    freopen("cash.out","w",stdout);

    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&day[i].a,&day[i].b,&day[i].r),day[i].num=i;
    sort(day+1,day+n+1,cmp);
    f[1]=s;solve(1,n);
    printf("%.3lf",f[n]);

    return 0;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章