前言
這是我寫的第一道$dp$斜率優化的題目,$dp$一直都很菜,而且咖啡雞都說了這是基礎的東西,然而看別人對$dp$斜率優化一大堆公式又看不懂就老老實實做幾道題目,這個比較實在
描述
給出$n$和$l$.有$n$個玩具,第$i$個玩具的長度是$c[i]$,要求將玩具分成若干段,從$i$到$j$分為一段的長度為$x=j-i+\sum_^c[k]$,費用為$(x-l)^$. 求最小費用 [link]
分析
用$dp[i]$表示前i個玩具所需的最小費用,則有
$dp[i]=min\left \(1<=j
其中$sum[i]$表示的是$c[i]$的字首和.
為了方便,我們設
$a[i]=sum[i]+i,l=l+1$
於是原方程就等價於
$dp[i]=min\left\(1<=j
我們設$j
$dp[k]+(a[i]−a[k]−l)^
在紙上寫寫畫畫,把式子開啟再變一下形,容易得到
$\frac]-[dp[j]+(a[j]+l)^]}$ $
是不是很像
$\frac-y_}-x_}$
的形式?
這玩意兒不就是斜率嗎?!我們設它為$g(k,j)$
我們可以發現$a[i]$是單調遞增的,所以所有決策可以轉化為二維空間上的點集.
也就是說$k$這個點和j這個點的連線的斜率如果小於$a[i]$,那麼$k$這個決策就更優.
那麼對於三個決策$a
1.如果$g(b,a)
2.如果$g(b,a)>=a[i]$,那麼$b$不是最優,最優可能是$a$或$c$.
所以我們在新加入乙個點的時候,就可以把它看作$c$,然後把所有這樣的$b$都去掉,直到$g(c,b)>g(b,a)$,所以我們需要處理的斜率是單調遞增的.
這樣我們就可以用乙個單調佇列分別維護隊首和隊尾啦.
code
#include #define ll long longview code#define empty (head>=tail)
const
int maxn = 5e4+10
;ll n, l, head, tail, j;
ll q[maxn], sum[maxn], s[maxn], f[maxn];
inline
double x(ll i)
inline
double y(ll i)
inline
double rate(ll i,ll k)
intmain()
head = tail = 1; q[1] = 0
;
for (int i = 1; i <= n; i++)
printf(
"%lld\n
", f[n]);
}
網上講了很多數形結合的方法,找截距最小,的確對理解很有幫助,但是可能像這樣的對我來說更好理解,另外有些細枝末節的東西沒有完全看懂,但是現在沒必要糾結.
建議多看些部落格,了解不同的想法,慢慢就會理解
這裡能用斜率優化是因為a[i]是單調的,至於具體為什麼,先不細究
參考文章:
HNOI2008 玩具裝箱toy
重點在講斜率優化 description p教授要去看奧運,但是他捨不下他的玩具,於是他決定把所有的玩具運到北京。他使用自己的壓縮器進行壓縮,其可以將任意物品變成一堆,再放到一種特殊的一維容器中。p教授有編號為1.n的n件玩具,第i件玩具經過壓縮後變成一維長度為ci.為了方便整理,p教授要求在乙個一...
HNOI2008 玩具裝箱toy
dp i min dp j sum i sum j c 2 dp k sum i sum k c 2 dp k si sum k 2 dp k si 2 2 si sum k sum k 2 dp k sum k 2 dp j sum j 2 2 si sum k sum j yk yj 2 si ...
HNOI2008 玩具裝箱TOY
題目描述 p教授要去看奧運,但是他捨不下他的玩具,於是他決定把所有的玩具運到北京。他使用自己的壓縮器進行壓縮,其可以將任意物品變成一堆,再放到一種特殊的一維容器中。p教授有編號為1 n的n件玩具,第i件玩具經過壓縮後變成一維長度為ci.為了方便整理,p教授要求在乙個一維容器中的玩具編號是連續的。同時...