[NOI2007] 货币兑换 (dp+李超树维护凸包)
description
小Y最近在一家金券交易所工作。該金券交易所只發(fā)行交易兩種金券:A紀(jì)念券(以下簡稱A券)和 B紀(jì)念券(以下簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數(shù)目可以是一個實數(shù)。每天隨著市場的起伏波動,兩種金券都有自己當(dāng)時的價值,即每一單位金券當(dāng)天可以兌換的人民幣數(shù)目。我們記錄第 K 天中 A券 和 B券 的價值分別為 AK 和 BK(元/單位金券)。為了方便顧客,金券交易所提供了一種非常方便的交易方式:比例交易法。比例交易法分為兩個方面:(a)賣出金券:顧客提供一個 [0,100] 內(nèi)的實數(shù) OP 作為賣出比例,其意義為:將 OP% 的 A券和 OP% 的 B券 以當(dāng)時的價值兌換為人民幣;(b)買入金券:顧客支付 IP 元人民幣,交易所將會兌換給用戶總價值為 IP 的金券,并且,滿足提供給顧客的A券和B券的比例在第 K 天恰好為 RateK;例如,假定接
下來 3 天內(nèi)的 Ak、Bk、RateK 的變化分別為:
假定在第一天時,用戶手中有 100元 人民幣但是沒有任何金券。用戶可以執(zhí)行以下的操作:
注意到,同一天內(nèi)可以進行多次操作。小Y是一個很有經(jīng)濟頭腦的員工,通過較長時間的運作和行情測算,他已經(jīng)知道了未來N天內(nèi)的A券和B券的價值以及Rate。他還希望能夠計算出來,如果開始時擁有S元錢,那么N天后最多能夠獲得多少元錢。
Input
輸入第一行兩個正整數(shù)N、S,分別表示小Y能預(yù)知的天數(shù)以及初始時擁有的錢數(shù)。接下來N行,第K行三個實數(shù)AK、BK、RateK,意義如題目中所述
對于100%的測試數(shù)據(jù),滿足:0<AK≤10;0<BK≤10;0<RateK≤100;MaxProfit≤0^9。
【提示】
1.輸入文件可能很大,請采用快速的讀入方式。
2.必然存在一種最優(yōu)的買賣方案滿足:
每次買進操作使用完所有的人民幣;
每次賣出操作賣出所有的金券。
Output
只有一個實數(shù)MaxProfit,表示第N天的操作結(jié)束時能夠獲得的最大的金錢數(shù)目
答案保留3位小數(shù)。
Sample Input
3 100
1 1 1
1 2 2
2 2 3
Sample Output
225.000
Hint
solution
乍一看跟以前做過的股票交易挺像的,這個式子長得就斜率優(yōu)化誘惑
Step1
貪心。。。
在某一天要么買股票把錢買完,要么賣股票把股票賣完
不會有人賺錢只賺一半就跑了吧
Step2
考慮列出狀態(tài)轉(zhuǎn)移方程
設(shè)fif_ifi?表示iii天能賺的最多的錢,aia_iai?為iii天最多能買的AAA股票數(shù),bib_ibi?為iii天最多能買的BBB股票數(shù)
①在iii天買入股票ai=fi×RateiAi×Ratei+Bi,bi=fiAi×Ratei+Bia_i=\frac{f_i\times Rate_i}{A_i\times Rate_i+B_i},b_i=\frac{f_i}{A_i\times Rate_i+B_i}ai?=Ai?×Ratei?+Bi?fi?×Ratei??,bi?=Ai?×Ratei?+Bi?fi??
②在iii天不買不賣
fi=max(fi,fi?1)f_i=max(f_i,f_{i-1})fi?=max(fi?,fi?1?)
③在iii天賣股票,枚舉在jjj天買入的股票
fi=max{aj?Ai+bj?Bi}f_i=max\{a_j*A_i+b_j*B_i\}fi?=max{aj??Ai?+bj??Bi?}
對式子進行變形
fi=max{Bi×(AiBi?aj+bj)}f_i=max\{B_i\times (\frac{A_i}{B_i}*a_j+b_j)\}fi?=max{Bi?×(Bi?Ai???aj?+bj?)}
Step3
李超線段樹維護凸包
將fif_ifi?的式子看作直線kx+bkx+bkx+b
k=aj,x=AiBi,b=bjk=a_j,x=\frac{A_i}{B_i},b=b_jk=aj?,x=Bi?Ai??,b=bj?
code
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 int n; double ans; double A[maxn], B[maxn], Rate[maxn], c[maxn], x[maxn], k[maxn], b[maxn]; int t[maxn << 2];double calc( int i, int pos ) {return k[i] * x[pos] + b[i]; }void modify( int num, int l, int r, int id ) {if( l == r ) {if( calc( id, l ) > calc( t[num], l ) ) t[num] = id;return;}int mid = ( l + r ) >> 1;if( calc( id, mid ) > calc( t[num], mid ) ) swap( t[num], id );if( calc( id, l ) > calc( t[num], l ) ) modify( num << 1, l, mid, id );if( calc( id, r ) > calc( t[num], r ) ) modify( num << 1 | 1, mid + 1, r, id ); }double query( int num, int l, int r, int pos ) {if( l == r ) return calc( t[num], pos );int mid = ( l + r ) >> 1;if( pos <= mid ) return max( calc( t[num], pos ), query( num << 1, l, mid, pos ) );else return max( calc( t[num], pos ), query( num << 1 | 1, mid + 1, r, pos ) ); }int main() {scanf( "%d %lf", &n, &ans );for( int i = 1;i <= n;i ++ ) {scanf( "%lf %lf %lf", &A[i], &B[i], &Rate[i] );x[i] = c[i] = A[i] / B[i];}sort( x + 1, x + n + 1 );for( int i = 1;i <= n;i ++ ) {int p = lower_bound( x + 1, x + n + 1, c[i] ) - x;ans = max( ans, B[i] * query( 1, 1, n, p ) );double g = A[i] * Rate[i] + B[i];k[i] = ans * Rate[i] / g, b[i] = ans / g;modify( 1, 1, n, i );}printf( "%.3f\n", ans );return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的[NOI2007] 货币兑换 (dp+李超树维护凸包)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果OLED屏iPad Pro真有望明年
- 下一篇: 苹果 iPhone 15 Pro Max