今天聽了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...