NOI2007 貨幣兌換

2022-05-02 02:00:15 字數 1443 閱讀 2256

設\(dp[i],a[i],b[i],x[i],y[i]\)為第\(i\)天時的最大收益/a卷**/b卷**/將所有現金兌成a卷數量/b卷

於是有\[dp[i]=\max(dp[i-1],x[j]*a[i]+y[j]*b[i])

\]然後可以寫成斜率優化形式

\[y[j]=-\fracx[j]+\frac

\]對於每個點\((x[j],y[j])\),我們用一根斜率為\(-\frac\)的直線去經過它,使截距最大,也就是維護上凸包

因為每一點x座標,斜率都不單調,所以上平衡樹 cdq

先把所有點按k遞增順序排好,再按天數分治,使得處理時是按天數遞增的順序

因為這是dp,所以要先處理左區間,再遞迴右區間

在處理影響時我們不用管左區間的順序,也就是可以按x座標遞增插入凸包裡

遞迴出口時首先\(dp[i]=\max(dp[i],dp[i-1])\),然後再計算\(y[i]=\frac,x[i]=y[i]*a[i]\)

加上歸併把複雜度降低到\(o(n\log n)\)

注意這道題似乎有點卡精度(雖然我沒有)

#includeusing namespace std;

#define maxn 100005

#define db double

#define eps 1e-9

#define inf 1e18

db dp[maxn];

int n, sta[maxn];

struct cash

friend void read(cash& p)

}cash[maxn], tp[maxn];

db getk(int a, int b)

void merge_sort(int l, int r, int mid)

while (t1 <= mid) tp[k++] = cash[t1++];

while (t2 <= r) tp[k++] = cash[t2++];

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

}void cdq(int l, int r)

int mid = (l + r) >> 1, top = 0;

for (int i = l, t1 = l, t2 = mid + 1; i <= r; ++i)//先按天數排序,遞迴

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

cdq(l, mid);

for (int i = l; i <= mid; ++i)//維護左區間的上凸包

for (int i = mid + 1; i <= r; ++i)//更新右區間答案

cdq(mid + 1, r);

merge_sort(l, r, mid);

}int main()

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