APIO2010 特别行动队 斜率优化DP算法笔记
做完此題之后 自己應該算是真正理解了斜率優化DP
根據狀態轉移方程$f[i]=max(f[j]+ax^2+bx+c),x=sum[i]-sum[j]$
可以變形為 $f[i]=max((a*sum[j]^2-b*sum[j])-(2a*sum[j]*sum[i]))+(a*sum[i]^2+b*sum[i]+c)$
我們可以把每個決策映射到平面上的一個點
其中坐標$x=(a*sum[j]^2-b*sum[j])$代表此決策的固定價值(與轉移到哪無關)
坐標$y=(-2a*sum[j])$代表此決策的潛在價值(與轉移到哪有關)?
這樣我們就可以開始用單調隊列維護一個$x$遞增 $y$遞減的凸殼
------------------------------------------------------------------------
對于每次加入進來的一個新元素
我們先對隊首的兩個決策進行判斷 若某決策現有價值不如后面的決策則將其刪去
(因為維護的單調隊列中的決策潛在價值是遞增的)
然后更新新加的元素的最大值
再對新加元素與隊尾的兩個決策間進行判斷
如果隊尾第一個的決策在新加決策和前面所有決策所構成凸殼之內
那么這個決策永遠不可能同時優于前一個決策和新加決策?所以就直接刪掉就好了
最后將新加的決策加入單調隊列
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define rep(i,n) for(int i=1;i<=n;++i) #define imax(x,y) (x>y?x:y) #define imin(x,y) (x<y?x:y) using namespace std; const int N=1000010; int sum[N],q[N]; long long f[N]; int n; long long a,b,c; long long solve(int x,int y) {return f[x]+a*(sum[y]-sum[x])*(sum[y]-sum[x])+b*(sum[y]-sum[x])+c; } long long solvex(int x) {return f[x]+a*sum[x]*sum[x]-b*sum[x]; } bool judge(int x,int y,int z) {long long tx=solvex(x),ty=solvex(y),tz=solvex(z);return (ty-tx)*(sum[z]-sum[x])<=(tz-tx)*(sum[y]-sum[x]);//約掉了-2a } int main() {scanf("%d",&n);scanf("%lld%lld%lld",&a,&b,&c);rep(i,n){scanf("%d",&sum[i]);sum[i]+=sum[i-1];}int ifront=1,itail=1;q[1]=0;rep(i,n){while(ifront<itail&&solve(q[ifront],i)<=solve(q[ifront+1],i))++ifront;f[i]=solve(q[ifront],i);while(ifront<itail&&judge(q[itail-1],q[itail],i))--itail;q[++itail]=i;}printf("%lld",f[n]);return 0; }?
轉載于:https://www.cnblogs.com/sagitta/p/4626683.html
總結
以上是生活随笔為你收集整理的APIO2010 特别行动队 斜率优化DP算法笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (王道408考研数据结构)第六章图-第二
- 下一篇: 操作系统之文件管理:6、文件的基本操作(