NOI2007 貨幣兌換

2022-05-15 13:48:03 字數 2494 閱讀 6282

目錄好像是二刷了吧,但是肯定不止見過兩次了。

傳送門 to luogu

不難發現 題目提示也給了 必定存在一種最優方案滿足**時用完所有錢,賣出時賣完所有**。

先分析清楚題,假如說在第 \(i\) 天用 \(s\) 元買**,那麼最後

\[\text_b=_i+b_i} \\

\text_a=\text_b\text_i=_i\over a_i\text_i+b_i}

\]那麼我們定義 \(f_i\) 表示第 \(i\) 天能夠得到的最多的錢,那麼就有乙個 \(\mathcal o(n^2)\) 的轉移:

\[f_i=\max_^\_j\over a_j\text_j+b_j}+b_i\times _j+b_j}\}

\]最後還要 \(f_i=\max\\}\) 表示今天什麼都沒乾,初始狀態 \(f_0=s\).

十分容易地拿下 \(60pts\),考慮優化這個 \(\mathcal o(n^2)\) 的 \(\tt dp\).

定義 \(t_i=a_i\text_i+b_i\),那麼轉移寫作

\[f_i=\max_^\_j\over t_j}+b_i\times \}

\]發現這兩個分數都只和 \(j\) 有關,那麼這個式子就是可以斜率優化的。

記 \(x_j=_j\over t_j},y_j=\),我們將這個方程改寫一下:

\[f_i=a_ix_j+b_iy_j \\

\rightarrow y_j=-x_j+

\]從含義上講,即對於之前的所有決策點,在平面上記其為 \(\lang x_j,y_j\rang\),然後用 \(-\) 的直線去任意切乙個,得到的最大截距就是 \(f_i\over b_i\),然後就可以算出最大 \(f_i\) 了。

但是有乙個問題,那就是這個 \(x_j\) 並不是單調的,所以我們還不能使用單調佇列對其進行維護,但是我們可以使用 \(\tt cdq\) 分治,每次把左邊的 \(x_i\) 進行排序,考慮左邊對右邊的貢獻,維護乙個不動凸包,然後在凸包上面二分即可,這樣做複雜度 \(\mathcal o(n\log^2 n)\). 其實也不需要再凸包上進行二分,只需要將右邊按照斜率 \(k=-\) 排序,每次在凸包前面檢視是否有更優解,有就將隊頭彈出,直到找到最優解更新答案即可。

#include#includeusing namespace std;

typedef long long ll;

templateinline t fab(const t x)

templateinline t readin(t x)

inline int operator ==(const double rhs) const

inline double operator -(const double rhs) const

inline double operator +(const double rhs) const

inline double operator *(const double rhs) const

inline double operator /(const double rhs) const

inline double operator -() const

} doub;

int n;

doub a[maxn+5], b[maxn+5], rate[maxn+5];

doub x[maxn+5], y[maxn+5], f[maxn+5];

inline void input()

}inline int comp(const doub a,const doub b)

inline int cmpx(const int i, const int j)

inline doub slope(const int i, const int j)

inline doub slope(const int i)

int q[maxn+5], op, ed;

int id[maxn+5];

void solve(const int l, const int r)

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

solve(l, mid);

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

sort(id+l, id+mid+1, cmpx);

sort(id+mid+1, id+r+1, cmpslope);

op=1, ed=0;

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

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

solve(mid+1, r);

}signed main()

有些地方精度太高了,調了好久......卡進度真的沒意思。

有時候斜率並不能保證一些東西是單調的,這個時候你就需要使用動態凸包或者用 \(\tt cdq\) 處理這種座標不保證單調的情況。

另外,對於 \(\tt dp\) 方程的變形,要將和 \(i\) 有關的,和 \(j\) 有關的變數進行剝離,這樣才能更好地處理。

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...