一道入门题
hdu3507
一行上打印连续k个单词的花费为
,
给你每个单词的花费 Ci,
求最后总的最小花费。
很容易想到的dp式是: dp[i]=min{dp[j]+(∑h=j+1iCh)2+M}
然而 n=500000 直接这么做的话肯定是做不到 O(1) 的。
于是把上面的式子变形一下,首先斜率优化是针对决策过程而不是dp的,所以关注 k<j<i 这个决策。
$$
dp[j] + (\sum_{h=j+1}^iC_h)^2 +M< dp[k] + (\sum_{h=k+1}^iC_h)^2+M
$$
其中 $\sum_{h=j+1}^iC_h$可以用前缀和来表示。
dp[j]+(presumi−presumj)2<dp[k]+(presumi−presumk)2
拆开变形,
dp[j]+presumj2−2∗presumj∗presumi<dp[k]+presumk2−2∗presumk∗presumi
(dp[j]+presumj2)−(dp[k]+presumk2)<2∗presumi∗(presumj−presumk)
2∗(presumj−presumk)(dp[j]+presumj2)−(dp[k]+presumk2)<presumi
令
g(j,k)=2∗(presumj−presumk)(dp[j]+presumj2)−(dp[k]+presumk2)
也就是说
g(j,k)<presumi⇔选取j优于k
g(j,k)>presumi⇔选取k优于j
那么从左到右,对 k<j<i ,如果
g(i,j)<=g(j,k)
此时如果在 α 点做决策。
g(i,j)>=presumα⇒g(j,k)>=presumα⇒选取k优于j
g(i,j)<presumα⇒选取i优于j
所以j点可以直接排除。
也就是说,对于做过优化的点集,要求
g(i,j)>g(j,k)
恒成立。对于一般的映射g,要维护这个性质需要 O(n2) 的复杂度。但是这里很多时候可以用斜率优化。。
斜率优化
g(j,k)=2∗(presumj−presumk)(dp[j]+presumj2)−(dp[k]+presumk2)
令 y(j)=dp[j]+presumj2,x(j)=2∗presumj,这里 x(j) 满足单调性,因此可以把 presum 离散化。
那 g(i,j) 满足
g(i,j)>g(j,k)
也就是对 x(j),y(j) ,后面的斜率比前面的斜率大,保持下凸性。
如上图。
这里维护点集的方法和求凸包时使用的方法一样,维护一个队列(栈),对每一个新加入的点,出栈直到
最后满足
g(i,i−1)>max{g(j,k)},j,k是已经在队列里面的点
求解的时候,
dp[i]=dp[Q.front]+(presumi−presumQ.front)2+M
此时,
i>j,g(j,j−1)>presumi
j 就是最优决策!