其他分享
首页 > 其他分享> > [NOI2007]货币兑换

[NOI2007]货币兑换

作者:互联网

[NOI2007]货币兑换

有n天,第i天有一个属性\(a_i,b_i,r_i\)表示当天股票a,b的价值分别为\(a_i,b_i\),且购买的a,b股票数量比值为\(a_i/b_i\),要求要卖股票要全部卖完,买股票要用完全部的钱,现在初始有s钱,为n天后最大的钱数,\(n ≤ 100 000\)。

设第j天能够购买股票a,b的数量分别为\(x_j,y_j\),拥有的钱数为\(f_j\),不难有

\(x_ja_j+y_jb_j=f_j\)

\(\frac{x_j}{y_j}=r_j\)

解得

\(x_j=\frac{r_jf_j}{r_ja_j+b_j},y_j=\frac{f_j}{r_ja_j+b_j}\)

因此有方程

\[f_i=_{0\leq j<i}x_ja_i+y_jb_i\]

边界:\(f_0=s\),其余无限小

答案:\(f_n\)

注意到式子需要优化,因为j,i的关系密切,考虑斜率优化,因此不难得知斜率优化式为

\[-y_j=\frac{a_i}{b_i}x_j-\frac{f_i}{b_j}\]

注意到\(b_j\)为正数,所以截距要尽可能小,但是不存在单调性,于是考虑set维护动态插点,删点,查斜率,时间复杂度\(O(nlog^n)\)。

参考代码:

#include <iostream>
#include <cstdio>
#include <set>
#define il inline
#define ri register
#define Size 100010
using namespace std;
bool control;
struct pi{
    double x,y,*k;
    il bool operator<(const pi&a)const{
        if(control)return x<a.x;
        return *k<*a.k;
    }
};set<pi>S;
il void add(int);
double a[Size],b[Size],r[Size],dp[Size];
template<class free>il free Max(free,free);
template<class free>il void Swap(free&,free&);
il double query(int),K(const pi&,const pi&);
int main(){
    int n,s;scanf("%d%d",&n,&s),dp[0]=s;
    for(int i(1);i<=n;++i)
        scanf("%lf%lf%lf",&a[i],&b[i],&r[i]),
            dp[i]=Max(dp[i-1],query(i)),add(i);
    printf("%.3lf",dp[n]);
    return 0;
}
il double K(const pi &a,const pi &b){
    return (a.y-b.y)/(a.x-b.x);
}
il void add(int i){
    control|=true;set<pi>::iterator M,A,B;
    pi m;m.x=dp[i]*r[i]/(a[i]*r[i]+b[i]);
    m.y=-m.x/r[i],m.k=new double,M=S.insert(m).first;
       A=B=M;if(A!=S.begin()&&(++B)!=S.end()){
        --A;if(K(*A,*M)>=K(*M,*B))return (void)(S.erase(M));
    }A=M,++A;
    while(A!=S.end())
        if(K(*M,*A)>=*A->k)B=A,++A,S.erase(B);
        else break;
    if(A==S.end())*M->k=1e100;
    else *M->k=K(*M,*A);
    A=M;if(A!=S.begin()){
        --A;while(A!=S.begin()){
            B=A,--B;if(*B->k>=K(*A,*M))Swap(A,B),S.erase(B);
            else break;
        }       
    }if(M!=S.begin())*A->k=K(*A,*M);
}
il double query(int i){
    control&=false;if(!S.size())return 0;set<pi>::iterator p;
    p=S.lower_bound((pi){0,0,new double(a[i]/b[i])});
    return p->x*a[i]-p->y*b[i];
}
template<class free>
il void Swap(free &a,free &b){
    free c(a);a=b,b=c;
}
template<class free>
il free Max(free a,free b){
    return a>b?a:b;
}

标签:int,double,free,NOI2007,兑换,il,货币,pi,Size
来源: https://www.cnblogs.com/a1b3c7d9/p/10976447.html