NOI2007 貨幣兌換

2022-08-20 02:03:15 字數 3070 閱讀 5840

小y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:a紀念券(以下簡稱a券)和 b紀念券(以下

簡稱b券)。每個持有金券的顧客都有乙個自己的帳戶。金券的數目可以是乙個實數。每天隨著市場的起伏波動,

兩種金券都有自己當時的價值,即每一單位金券當天可以兌換的人民幣數目。我們記錄第 k 天中 a券 和 b券 的

價值分別為 ak 和 bk(元/單位金券)。為了方便顧客,金券交易所提供了一種非常方便的交易方式:比例交易法

。比例交易法分為兩個方面:(a)賣出金券:顧客提供乙個 [0,100] 內的實數 op 作為賣出比例,其意義為:將

op% 的 a券和 op% 的 b券 以當時的價值兌換為人民幣;(b)**金券:顧客支付 ip 元人民幣,交易所將會兌

換給使用者總價值為 ip 的金券,並且,滿足提供給顧客的a券和b券的比例在第 k 天恰好為 ratek;例如,假定接

下來 3 天內的 ak、bk、ratek 的變化分別為:

假定在第一天時,使用者手中有 100元 人民幣但是沒有任何金券。使用者可以執行以下的操作:

注意到,同一天內可以進行多次操作。小y是乙個很有經濟頭腦的員工,通過較長時間的運作和**測算,他已經

知道了未來n天內的a券和b券的價值以及rate。他還希望能夠計算出來,如果開始時擁有s元錢,那麼n天後最多能

夠獲得多少元錢。

input

輸入第一行兩個正整數n、s,分別表示小y能預知的天數以及初始時擁有的錢數。接下來n行,第k行三個實數ak、b

k、ratek,意義如題目中所述。對於100%的測試資料,滿足:01.輸入檔案可能很大,請採用快速的讀入方式。

2.必然存在一種最優的買賣方案滿足:

每次買進操作使用完所有的人民幣;

每次賣出操作賣出所有的金券。

只有乙個實數maxprofit,表示第n天的操作結束時能夠獲得的最大的金錢數目。答案保留3位小數。

3 100

1 1 1

1 2 2

2 2 3

225.000

不是這題為啥那麼噁心為啥還要拿個資料結構來維護凸包然後還那麼難調浪費了我半天的時間還去網上抄的題解

這道題一開始沒看見提示然後還推了半天暴力dp

設x[i] , y[i]表示第i天最多能買多少a劵,b劵

f[i]表示第i天的最大收益

然後dp式子肥腸明顯

\(x[i] = \frac\)

\(y[i] = \frac\)

\(f[i] = a[i] * x[j] + b[i] * y[j]\)

然後60pts就到手了

化簡個式子

就可以得到$-\frac + \frac = y[j] $

那麼是不是\(k = -\frac , x = x[j] , b = \frac , y = y[j]\)

答案都在乙個凸包上

那這樣是不是就可以斜率優化了??

所以我就肥腸眼瞎的用單調佇列寫了一發 , 開心的得到了20pts

然而 x[j] 並不單調==

因為每天能買到的a劵的上限不是單調遞增的

所以我眼瞎

我們可以考慮用乙個資料結構來維護

可以用平衡樹或者cdq來維護這個凸包

但是由於平衡樹維護凸包難 不會 寫

所以使用cdq維護凸包

考慮每一天的x只能對這一天及以後的天產生影響

所以我們先對k排序(因為要保證斜率單調下降)

然後我們使用cdq分治的時候就用左邊一半來更新右邊一半的答案

最後再把左右兩邊按照x單增排序

這樣就可以解決x不單調的問題了

#include#include#include#includeconst double inf = 1e18 ;

const int m = 100005 ;

const double eps = 1e-8 ;

using namespace std ;

int n , top , st[m] ;

double f[m] ;

struct node p[m] , t[m] ;

inline double x(int i)

inline double y(int i)

inline double slope(int i , int j)

inline bool operator < (node a , node b)

inline void solve(int l , int r)

int mid = (l + r)>>1 ;

int tl = l , tr = mid + 1 ;

for(int i = l ; i <= r ; i ++)

if(p[i].id <= mid) t[tl++] = p[i] ;

else t[tr++] = p[i] ;

for(int i = l ; i <= r ; i ++) p[i] = t[i] ;

solve(l , mid) ;

int tail = 0 ;

for(int i = l ; i <= mid ; i ++)

int head = 1 ;

for(int i = mid + 1 ; i <= r ; i ++)

solve(mid + 1 , r) ;

tl = l , tr = mid + 1 ;

for(int i = l ; i <= r ; i ++)

if(( (p[tl].x < p[tr].x) || (fabs(p[tl].x - p[tr].x) < eps && p[tl].y < p[tr].y) || tr > r ) && tl <= mid ) t[i] = p[tl++] ;

else t[i] = p[tr++] ;

for(int i = l ; i <= r ; i ++) p[i] = t[i] ;

}int main()

sort(p + 1 , p + n + 1) ;

solve(1 , n) ;

printf("%lf\n",f[n]) ;

return 0 ;

}

NOI2007 貨幣兌換

今天聽了crazy和samjia的noi雜 砸 題選講,感覺自己萌萌噠 於是就來怡情地寫了這道題。額 o 這個不好說啊。語文不好不好裱我 還是貼圖吧。咳咳,希望大家都看懂題了。乙個很明顯的貪心思路就是,我們每天要不全買,要不全賣。因為一有利益我們就去佔,一有虧損我們就不碰。那麼我們可以有dp方程 f...

Noi2007 貨幣兌換

傳送門 小半個上午 一下午都給了這題了qaq 都知道是斜率優化,問題是我看這題根本就是乙個人乙個式子啊 算了,把我的過程列出來吧 令 f i 表示第i天結束時強制賣出所有金券最多能得到的軟妹幣數量,列舉上一次 金券的時間,就有 beginf i max end 這裡沒有寫隱含條件 f i ge f ...

NOI2007 貨幣兌換

題目 先來畫一畫柿子 設 dp i 表示你第 i 天之後最多剩下多少錢 考慮一下對於 i 的轉移,我們肯定要在之前列舉一天 j 這一天把所有的東西買進來,之後在 i 天賣掉 設那天買進 a 的量為 d a 買進 b 的量為 d b 我們可以得到這樣的方程 d ap a d bp b dp j d a...