用来存下板子。。。证明或详细讲解请参考其他blog
决策单调性
可离线
分治
例:CF321E
1 2 3 4 5 6 7 8 9
| void solve(int s,int l=1,int r=n,int nl=0,int nr=n-1) { if(l>r) return; int m = mid,from; f[s][m]=inf; fp(i,nl,min(nr,m-1)) if(f[s-1][i]+cost(i+1,m)<f[s][m]) f[s][m]=f[s-1][i]+cost(i+1,m),from=i; solve(s,l,m-1,nl,from),solve(s,m+1,r,from,nr); }
|
不可离线
写法参考自:浅析1D1D动态规划的优化
确定 $f[3]$ 之前所有状态的最优决策表:
1111111111111222222222222
加入 $f[3]$ 后决策表只能有三种类型
1111111111111222222222222 不变
1111111111111222223333333 占据 $2$ 的一部分
1111113333333333333333333 完全覆盖 $2$
考虑使用栈来维护每个 $i$ 作为决策点的起始位置
设老决策的起点为 $j$,从栈顶向下依次考虑:
若新决策在 $j$ 优于老决策,则退栈并抛弃老决策
否则,转折点一定在当前这个老决策的区间中,二分这个位置
新决策入栈
例: [NOI2009]诗人小G
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| pr s[MAXN]; int h=0; LL calc(int i,int j){return f[j]+cost(i,j);} fp(i,1,n) { pr t=*(ub(s+1,s+h+1,mp(i,inf))-1);
f[i]=calc(i,t.se),from[i]=t.se; if(i==n||calc(n,s[h].se)<calc(n,i))continue;
while(h&&s[h].fi>i&&calc(s[h].fi,s[h].se)>calc(s[h].fi,i))h--; int l=max(i+1,s[h].fi),r=n,ans=n; while(l<=r) { if(calc(mid,s[h].se)>calc(mid,i))ans=mid,r=mid-1; else l=mid+1; } s[++h]={ans,i}; }
|