今天考场上突现决策单调性
原本对这个算法表示摒弃的本弱突然被打击了
于是来学习学习...
原理
我们只考虑$1D;|;1D$的动态规划...
同时,我们讨论这么一类$dp$:$f[i] = min(f[j] + w(j, i))(1 leqslant j leqslant i - 1)$
($max$同理)
我们记$w(i, j)$表示从$i$转移到$j$的代价
决策单调性是指对于$a < b < c < d$
如果$c$从$b$转移过来比从$a$转移过来更优
那么$d$从$b$转移过来比从$a$转移过来更优
用两个不等式来表达:
$$f[b] + w(b, c) leq f[a] + w(a, c)...(1)$$
$$f[b] + w(b, d) leq f[a] + w(a, d)...(2)$$
如果我们有$$w(b, d) - w(b, c) leq w(a, d) - w(a, c)...(3)$$
那么我们就能由$(1) + (3)$得到$(2)$
考虑对$(3)$式化简,即$$w(b, d) + w(a, c) leq w(a, d) + w(b, c)...(4)$$
这就是著名的四边形不等式
如果我们考虑用图形来表达,那么可以简记为“交叉”和“包含”的关系
这张图十分的形象
一般而言,$1D ;|1D$决策单调性的特点是没有特点
大致意思是,如果存在一个$dp$方程满足$1D;|;1D$
但是无法用斜率优化 / 前缀和 / $wqs$二分 / 数据结构优化...那么就可以考虑决策单调性
比较著名的例题
$[HNOI2008]$玩具装箱
非常显然的有$f[i] = min(f[j] + (i - j - 1 - L + s[i] - s[j])^2) (0 leqslant j < i)$
令$w(j, i) = (i - j - 1 - L + s[i] - s[j])^2$
我们考虑证明$w(a, c) + w(b, d) leq w(a, d) + w(b, c)$
$w(a, c) + w(b, d) = (c - a - L + s[c] - s[a])^2 + (d - b - L + s[d] - s[b])^2$
$w(a, d) + w(b, c) = (d - a - L + s[d] - s[a])^2 + (c - b - L + s[d] - s[c])^2$
对比上下两式,我们就能证明了
式子太长了不写了
我们引入一道平时训练的题,即$CF868F...$
非常明显的,我们设$f[i][j]$表示$1 sim i$中,划分了$j$段的最小代价
那么有$f[i][k] = min(f[j][k - 1] + w(j, i))(1 leqslant j leqslant i)$
我们考虑证明$w(b, d) + w(a, c) leq w(b, c) + w(a, d)$,就能证明决策单调性
我们设第$i$种颜色在段$[a, b)$中出现了$x$次,在$[b, c)$中出现了$y$次,在$[c, d)$中出现了$z$次
那么$w(b, d) + w(a, c) = inom{x + y}{2} + inom{y + z}{2}$
同时$w(a, d) + w(b, c) = inom{x + y + z}{2} + inom{y}{2}$
左式$ = x^2 + 2y^2 + z^2 + 2xy + 2yz - x - 2y - z$
右式$ = x^2 + 2y^2 + z^2 + 2xy + 2yz + 2xz - x - 2y - z$
那么如果左式$leq$右式,那么有$-x-2y-z leq 2xz - x - 2y - z$
这显然成立,由于对每个颜色都满足这个不等式,因此四边形不等式是成立的
所以证明决策单调性没有想象中的那么困难...
实现决策单调性
我们分两种情况来讨论,我们考虑有$n$个决策点和$m$个被决策点
第一种情况,决策点和被决策点互相独立(yjq教会了我分治,却没有告诉我它的作用是有限的)
即,被决策点在将来不会成为决策点
这时,我们可以考虑用分治来解决,复杂度为$O(n log m + m)$
void solve(int l, int r, int L, int R) { if(l > r) return; //现在我们知道[L, R]的点可以决策[l, r]的点 int pos = -1, mid = (l + r) >> 1; //我们寻找出mid的最优决策点 for(int i = L; i <= min(R, mid - 1); i ++) if(g[i] + w(i, mid) < f[mid]) f[mid] = g[i] + w(i, mid), pos = i; //g与f无关!!! //w(i, j)表示从i转移到j的代价 //找出mid的最优决策点后 //[l, mid - 1]的决策点区间落在[L, pos]中 //[mid + 1, r]的决策点区间落在[pos, R]中 solve(l, mid - 1, L, pos); solve(mid + 1, r, pos, R); //递归即可 }
同时在这时,如果$w(i, j)$不好$O(1)$的计算
但是,用类似于莫队的方式十分好维护
那么我们仍然可以在$O(n log m + m log m)$的时间内解决这个问题
int nl, nr; int w(int i, int j) { while(nl > i) ...; while(nl < i) ...; while(nr > j) ...; while(nr < j) ...; return ...; } void solve(int l, int r, int L, int R) { if(l > r) return; int pos = -1, mid = (l + r) >> 1; for(int i = L; i <= min(R, mid - 1); i ++) if(g[i] + w(i, mid) < f[mid]) f[mid] = g[i] + w(i, mid), pos = i; solve(l, mid - 1, L, pos); solve(mid + 1, r, pos, R); }
复杂度的证明:分治树总共有$log$层,在每一层内两个指针把决策点树和被决策点树都扫了一遍
第二种情况,决策点和被决策点互相影响
即,被决策点在将来会成为决策点
这时,我们可以采用二分 + 单调栈来优化,复杂度和分治同样,为$O(n log m + m)$
我们可以用经常举的例子,一开始
$1 sim n$对于$1 sim i$内的决策点在$i = 1$时
一定长成这个样子:111111111111111111111111111111111111111111
我们可以确定出$2$的最优取值,加入$2$
这时,我们可以发现,$1 sim n$的决策点会更变为这个样子
11111111111111111111222222222222222222222222
这时,我们又可以确定出$3$的最优取值,然后就会变成
11111111111111111111222222222222333333333333
依次类推,每次寻找新的分界的过程可以二分
特别的,以$3$为例,如果加入$3$后,变成了
1111111111111111111133333333333333333333
这时,我们需要弹掉$2$的决策区间,用栈可以维护
也就是说,用栈+二分来维护即可
略微的比分治要难写一点
//二分出当前可以转移到哪些点 int find(int x) { int l = lp[top], r = n; while(l <= r) { int mid = (l + r) >> 1; if(w(x, mid) < w(go[top], mid)) r = mid - 1; else l = mid + 1; } return l; } void solve() { int tra = top = 1; lp[1] = 1; go[1] = 0; //lp : 当前栈元素的转移区间的左端点 //go : 当前栈元素的转移区间由谁来转移 for(ri i = 1; i <= n; i ++) { if(i == lp[tra + 1]) tra ++; dp[i] = w(go[tra], i); while(w(i, lp[top]) < w(go[top], lp[top])) top --; int tmp = find(i); if(tmp <= n) lp[++ top] = tmp, go[top] = i; } }
决策单调性的题目并不多,写几道就差不多知道套路了
而且你知道了是决策单调性就简单了不少
习题
还是给出几道题目供大家练手吧...
$[HNOI2008]$ 玩具装箱
$[NOI2009]$ 诗人小G
$51nod1789$ 跑的比谁都快
$bzoj5125$ 小Q的书架
$CF868F$ Yet Another Minimization Problem
$51nod1488$ 帕斯卡小三角(存在决策单调性)