傳送門
首先有乙個顯然的貪心,每次操作都要做到底,為了最優不會出現只賣一部分或者只買一部分的操作
所以設 $f[i]$ 表示前 $i$ 天得到的最大價值,那麼對於每乙個 $i$,列舉所有 $j
顯然如果知道 $f[j]$,那麼就知道第 $j$ 天**多少
設 $a$ 買了 $x$, $b$ 買了 $y$,那麼 $f[i]=a[i]*x+b[i]*y$
因為 $x,y$ 只和 $j$ 有關,顯然可以斜率優化
具體就是 $-a[i]*x+f[i]=b[i]*y$,同除乙個 $b[i]$,變成 $-a[i]/b[i]*x+f[i]/b[i]=y$
那麼 $k=-a[i]/b[i],x=x,b=f[i]/b[i],y=y$
自己推一下,容易得出 $x_i=f[i]*r[i]/(a[i]*r[i]+b[i]),y_i=f[i]/(a[i]*r[i]+b[i])$
然後因為 $k,x$ 都不單調,所以要用 $cdq$ 搞
先按斜率排序,然後 $cqd$ 分治之前按下標拆成兩部分,這個具體還是看**吧...
#include#include#include
#include
#include
using
namespace
std;
typedef
long
long
ll;typedef
double
db;inline
intread()
while(ch>='
0'&&ch<='
9')
return x*f;
}const
int n=2e5+7,inf=1e9+7
;const db eps=1e-9
;int
n,s;
db f[n];
struct
dat}t[n],tmp[n];
inline db slope(
int i,int j)//
求斜率維護凸包
inline db cross(db xa,db ya,db xb,db yb) //
用叉積維護凸包會更快
inline void merge(int l,int r,int mid)//
按x歸併排序
for(int p=l;p<=r;p++) t[p]=tmp[p];
}int q[n];//
棧,維護凸包
void cdq(int l,int
r)
int mid=l+r>>1,pl=l,pr=mid+1,top=0
;
for(int p=l;p<=r;p++)//
按下標分開
for(int p=l;p<=r;p++) t[p]=tmp[p];
cdq(l,mid); q[
0]=0;//
先處理左邊
for(int i=l;i<=mid;i++)//
此時左邊全部更新完畢,可以維護左邊構成的凸包了
//注意此時左邊的t[i].x是有序的,因為每次cdq結束都會merge
for(int i=mid+1;i<=r;i++)//
用左邊構成的凸包更新右邊,此時右邊的斜率是有序的
cdq(mid+1,r); merge(l,r,mid);//
處理右邊後按x排序
}int
main()
sort(t+1,t+n+1); cdq(1,n);//
先按k排序再cdq
printf("
%.3lf
",f[n]);
return0;
}
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...