NOI2007 貨幣兌換

2021-07-16 18:54:28 字數 2099 閱讀 3667

今天聽了crazy和samjia的noi雜(砸)題選講,感覺自己萌萌噠~

於是就來怡情地寫了這道題。

額(⊙o⊙)…,這個不好說啊。(語文不好不好裱我)

還是貼圖吧。

咳咳,希望大家都看懂題了。

乙個很明顯的貪心思路就是,我們每天要不全買,要不全賣。

因為一有利益我們就去佔,一有虧損我們就不碰。

那麼我們可以有dp方程:f[

i]=m

ax(x

[j]∗

a[i]

+y[j

]∗b[

i],f

[i−1

])因為你一天可以什麼都不淦。

其中x[i]表示第i天最多能獲得的a卷數量,y[i]表示b卷數量。 那麼x

[i]=

f[i]

/(a[

i]∗r

ate[

i]+b

[i])

∗rat

e[i]

y[i]=f[

i]/(

a[i]

∗rat

e[i]

+b[i

])這樣dp是n^2的,我們考慮優化。

設j是最優決策,那麼f[

i]=x

[j]∗

a[i]

+y[j

]∗b[

i]於是y[

j]=−

a[i]

b[i]

x[j]

+f[i

]b[i

] 發現這是一次函式的形式。我們想讓截距最大。

於是我們可以維護乙個凸包,因為斜率一定,使截距最大的點一定在凸包上。

以x為x軸,y為y軸建立平面直角座標系。

但是,x[i]和-a[i]/b[i]不見得單調。

所以我們就是要動態維護乙個凸包,然後求某個斜率的位置。

splay**好!splay**好!splay**好!

你每次找到i左邊最後乙個斜率使得它仍然遞增的點,和右邊第乙個使得它遞增的的點。

然後刪點就好了。不要忘了判斷加上這個點後是否還是凸包。

#include

#include

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

#define n 100005

using

namespace

std;

typedef

double db;

const db inf=0x7fffffff;

const db ep=1e-5;

int n,fa[n],t[n][2],root;

db f[n],x[n],y[n],a[n],b[n],r[n],lk[n],rk[n];

int son(int x)

void rotate(int x)

void splay(int x,int y)

if (!y) root=x;

}void insert(int &v,int f,int id)

if (x[id]<=x[v]+ep) insert(t[v][0],v,id);

else insert(t[v][1],v,id);

}db getk(int i,int j)

int pre(int x)

int suc(int x)

void updata(int x) else lk[x]=inf;

if (t[x][1]) else rk[x]=-inf;

if (lk[x]<=rk[x]+ep)

}int find(int v,db k)

int main()

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

}

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

NOI2007 貨幣兌換

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