记录编号 455378 评测结果 AAAAAAAAAA
题目名称 [NOI 2007]货币兑换 最终得分 100
用户昵称 GravatarCooook 是否通过 通过
代码语言 C++ 运行时间 1.341 s
提交时间 2017-10-01 21:37:36 内存使用 6.04 MiB
显示代码纯文本
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 100005
const double eps = 1e-7;
int n,s,L[MAXN],R[MAXN],que[MAXN]; double a[MAXN],b[MAXN],rate[MAXN],f[MAXN],Ans[MAXN],fr[MAXN];


inline bool cmp_f(int a,int b){
    return f[a] < f[b];
}

inline bool cmp_xl(int x,int y){
    return a[x] / b[x] < a[y] / b[y];
}

inline double K(int x,int y){
    return (fr[x] - fr[y]) / (f[x] - f[y]);
}

inline bool Cmp(int x,int y,int z){
    if(f[x] == f[y]) return fr[x] >= fr[y];
    return K(z,x) >= K(y,x);
}

inline void CDQ(int l,int r){
    if(l == r) {
        fr[l] = f[l] / rate[l];
        return;
    }
    register int mid = l + r >> 1,front = 1,back = 0; CDQ(l,mid);
    for(int i = l;i<=mid;i++) L[i] = i; std::sort(&L[l],&L[mid+1],cmp_f);
    for(int i = mid+1;i<=r;i++) R[i] = i; std::sort(&R[mid+1],&R[r+1],cmp_xl);
    for(int i = l;i<=mid;i++) {     
        while(front < back && Cmp(que[back - 1],que[back],L[i])) back --;
        que[++back] = L[i];
    }
    for(int i = mid+1;i<=r;i++) {
        while(front < back && K(que[front],que[front+1]) > -a[R[i]] / b[R[i]]) front ++;
        double now = f[que[front]] * a[R[i]] + fr[que[front]] * b[R[i]];
        Ans[R[i]] = std::max(Ans[R[i]],now);
    }
    for(int i = mid+1;i<=r;i++) 
        Ans[i] = std::max(Ans[i-1],Ans[i]),f[i] = std::max(f[i],Ans[i] * rate[i] / (a[i] * rate[i] + b[i]));
    CDQ(mid+1,r);
}

int main(){
    freopen("cash.in","r",stdin);
    freopen("cash.out","w",stdout);
    scanf("%d%lf",&n,&Ans[1]);
    for(int i = 1;i<=n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&rate[i]);
    f[1] = Ans[1] * rate[1] / (a[1] * rate[1] + b[1]);
    CDQ(1,n); printf("%.3f\n",Ans[n]);
    // getchar(); getchar();   
    return 0;
}

//  num * a[i] + num/rate[i] * b[i] = s
//  (a[i] + 1/rate[i]*b[i]) * num = s;
//  num = s / (a[i] + 1/rate[i]*b[i]);
// Ans = s;
// for(int i = 2;i<=n;i++) {
//     for(int j = 1;j<i;j++) {
//         double now = f[j] * a[i] + f[j] / rate[j] * b[i];
//         Ans = std::max(Ans,now);
//     }
//     f[i] = Ans * rate[i] / (a[i] * rate[i] + b[i]);
// }
//  --> k > j
//  --> now[j] = f[j] * a[i] + f[j] / rate[j] * b[i]
//  --> now[k] = f[k] * a[i] + f[k] / rate[k] * b[i]
//  --> a[i] * (f[j] - f[k]) + (f[j] / rate[j] - f[k] / rate[k]) * b[i] > 0
//  --> a[i] * (f[k] - f[j]) < (f[j] / rate[j] - f[k] / rate[k]) * b[i]
//  --> (f[j] / rate[j] - f[k] / rate[k]) / (f[k] - f[j]) > a[i] / b[i]
//  --> (fr[j] - fr[k]) / (f[j] - f[k]) < - a[i] / b[i]
//  --> f[j] 不单调递增
//  --> CDQ分治,若 j 能更新 i 则 j < i && 上面辣个式子成立
//  --> 则以坐标为时间轴 进行CDQ 分治