考慮如下\(dp\):
\(dp(i)=max/min(a(i)+b(j)+c(i)d(j))\)
\((j < i)\)
其中,a(i),c(i)只與i有關,b(j),d(j)只與j有關。
括號裡有與i,j同時有關的項,導致單調佇列優化失效,但是如果這樣的項只有乙個可以採用斜率優化。方法如下:
將此dp方程轉化為\(dp(i)-a(i)=max/min(b(j)-c(i)(-d(j)) )\)的形式。
設b=dp(i)-a(i),y=b(j),k=c(i),x=-d(j)
即\(b=y-kx\),這時,只要使b最小/最大,就能使結果最小/最大。
移項,得\(y=kx+b\),轉化為直線的形式。每計算完乙個j就可以計算出對應的x,y.
其實就是把要最優的值設為b,只和j相關的項設為y,同時相關的設為kx。
還有類似\(b=ay-kx\)的形式(兩項相關),只要轉為\(b/a=y-(k/a)*x\)即可。
以最大為例(最小類似),現在就是要在所有的(x,y)中找出一對使得b最大。
把(x,y)表示為座標系中點的形式,就是找乙個點使得斜率為k的直線經過這個點時與y軸的交點的y座標盡量大。
可以發現把斜率為k的直線放在無限高處,再向下平移,接觸到的第乙個點就是結果。
如圖:
因為要求最大值,所以只有上凸包上的點有可能成為最大值,其他點可以刪除。
這時,紅色箭頭即為b,綠色箭頭即為最優的(x,y)。dp(i)就是b+a(i)。
如果x單調,k也單調,就可以用佇列或棧來維護凸包。(時間複雜度\(o(n)\))
如果k不單調,可以在凸包上二分,找到第乙個斜率小於k的位置,並計算解。(時間複雜度\(o(nlogn)\))
如果x不單調,可以用splay維護凸包,或利用cdq分治,在每層將x,k排序,使x,k遞增。(時間複雜度\(o(nlogn)\))
例題:bzoj1911[apio2010] 特別行動隊
設 f[i] 表示將前 i 個分組的最優值,則有轉移方程式:
\(f[i]=max( f[j]+a×(c[i]-c[j])^2+b×(c[i]-c[j])+c )\)
經過化簡得到:
\(f[i]=max( f[j]+a×c[j]^2-b×c[j]-2×a×c[i]×c[j]+a×c[i]^2+b×c[i]+c )\)
設\(a(i)=a×c[i]^2+b×c[i]+c\)
\(b(j)=f[j]+a×c[j]^2-b×c[j]\)
\(c(i)=2×a×c[i]\)
\(d(j)=-c[j]\)
就可以進行斜率優化了。且x單調遞增,k單調遞減,可以使用佇列維護凸包。
**:
#include #define ll long long
ll dp[1000010];
int sz[1000010],s[1000010];
ll x[1000010],y[1000010],he=0,ta=0;
int main()
for(int i=0;i<=n;i++)
printf("%lld",dp[n]);
return 0;
}
斜率優化總結
斜率優化是用於優化一些線性dp,主要思想類似於凸包。下面來看乙個例題 hdu 3507 由題意不難想到是dp,也很容易退出轉移過程f i m in f j s i s j 2 m i 0 i 1 但是一看 n 的範圍馬上就萎了,下面來看看用斜率怎麼優化。現將推出的轉移方程化簡 f i m in f ...
斜率優化總結
題目 luogu p2365 任務安排 題解 題解 p2365 任務安排 對於此類方程 f i begin f j val i,j end 暫時忽略min和範圍得 f i f j val i,j 整理得 f j val i,j f i 令 val i,j f i g j h i 則 f j f i ...
斜率優化總結
首先,推薦乙個大佬的部落格,講解非常詳細,所以不會斜率優化的請移步這裡,本部落格主要講題目分析qwq 主要講解題目 1.hnoi2008玩具裝箱 2.zjoi2007倉庫建設 3.usaco08mar土地徵用land acquisition 4.apio2010特別行動隊 下面,開始吧。題目分析 如...