Noi2007 貨幣兌換

2022-02-27 14:04:09 字數 2691 閱讀 8664

傳送門

小半個上午+一下午都給了這題了qaq……

都知道是斜率優化,問題是我看這題根本就是乙個人乙個式子啊(╯‵□′)╯︵┻━┻

算了,把我的過程列出來吧……

令$f[i]$表示第i天結束時強制賣出所有金券最多能得到的軟妹幣數量,列舉上一次**金券的時間,就有

\beginf[i]=\max_^\\end

(這裡沒有寫隱含條件$f[i]\ge f[i-1]$,記得更新完所有決策之後對下乙個$f$取一下$\max$即可。)

其中$x,y$分別表示用f[j]的軟妹幣能買到的a券和b券的數量,手動解乙個二元一次方程組之後可以得到轉移方程

\beginf[i]=\max_^\\}\end

令$g[i]=\frac$,轉移方程變為

\beginf[i]=\max_^\\end

考慮用哪些決策更新$f[i]$會比其他決策更優,設決策$k$比$j$更優,那麼有

\begin(a_ir_k+b_i)g[k]>(a_ir_j+b_i)g[j]\end

移項得\begina_i(r_kg[k]-r_jg[j])>b_i(g[j]-g[k])\end

假設$g[k]>g[j]$,左右同除$a_i(g[j]-g[k])$(顯然這個東西一定是負數),得

\begin\frac

令$x_i=g[i],y_i=-r_ig[i]$,然後就是標準的斜率$x_j$,畫個圖可以發現最優決策點一定處在下凸殼上,平衡樹維護凸殼或者cdq分治即可。鑑於沒寫過平衡樹維護凸殼(主要是不太會寫用一條直線去切凸殼的操作……),就用cdq分治好了。

每層分治時先遞迴左邊計算出左邊的所有$f$值,然後用左邊的凸殼更新右邊的所有$f$,之後遞迴右邊計算出右邊的所有$f$值,這時區間內所有點的座標都已知了,線性歸併左右兩個凸殼即可。為了保證複雜度需要先歸併排序預處理所有點對應詢問的斜率,用左邊更新右邊時離線掃瞄凸殼並更新決策。

**裡的$t$是預處理時每層按斜率排序之後的編號,$a$是用來存凸殼的,$s$是算凸殼的時候用到的棧。

1 #include2 #include3 #include4 #include5

using

namespace

std;

6const

int maxn=100010;7

const

long

double eps=1e-7;8

void mergesort(int,int,int);9

int cdq(int,int,int

);10

long

double getk(int,int

);11

long

double w(int,int

);12

long

double

a[maxn],b[maxn],r[maxn],f[maxn],x[maxn],y[maxn],k[maxn];

13double

tmp;

14int n,t[20

][maxn],a[maxn],s[maxn];

15int

main()

29 mergesort(1,n,0

);30 cdq(1,n,1

);31 printf("

%.3lf

",(double

)f[n]);

32return0;

33}34void mergesort(int l,int r,int

d)39

int mid=(l+r)>>1

;40 mergesort(l,mid,d+1

);41 mergesort(mid+1,r,d+1

);42

int i=l,j=mid+1,p=l;

43while(i<=mid&&j<=r)

47while(i<=mid)t[d][p++]=t[d+1][i++];

48while(j<=r)t[d][p++]=t[d+1][j++];49}

50int cdq(int l,int r,int

d)58

int mid=(l+r)>>1,cntl=cdq(l,mid,d+1),i=l,j=mid+1;59

while(i1&&j<=r)65}

66while(j<=r)

70int cntr=cdq(mid+1,r,d+1),cnt=l-1

;71 i=l;j=mid+1;72

while(icntr)

77else

if(x[a[i]]

81else85}

86while(icntl)

90while(j<=mid+cntr)

94 copy(s+l,s+r+1,a+l);

95return cnt-l+1;96

}97 inline long

double getk(int i,int j)

98 inline long

double w(int j,int i)

view code

寫了一下午,除去一些腦殘錯誤,最重要的是推式子的時候兩邊同乘/除的數的正負性一!定!要!確!定!……

好不容易把cdq分治全改對了,發現還是會wa,然後發現自己推的式子裡兩邊同除了乙個可能為正也可能為負的東西,然後斜率式子的不等號就不確定了……重新推了乙個式子才過的,多謝後世人,戒之慎勿忘……

NOI2007 貨幣兌換

今天聽了crazy和samjia的noi雜 砸 題選講,感覺自己萌萌噠 於是就來怡情地寫了這道題。額 o 這個不好說啊。語文不好不好裱我 還是貼圖吧。咳咳,希望大家都看懂題了。乙個很明顯的貪心思路就是,我們每天要不全買,要不全賣。因為一有利益我們就去佔,一有虧損我們就不碰。那麼我們可以有dp方程 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...