QOJ-5500 条形:从广义斜率优化到共同支配
从决策树到永久支配引理——QOJ 5500 的另一种理解
写在前面:本文核心证明较大部分由 AI 生成,人工核验。其余部分为人工。
模拟赛考了这道题,众所周知我一直不会建模和最优子结构,果断地列 dp 式,果断地瞪能否优化,果断地挂掉了。
下课后,我和一位超越凡俗的存在(GPT 6.0-Ast)彻夜长谈,于梦中灵光乍现,想到了一些好玩的东西。
题面
有一个数轴,上有 \(n\) 个点 $ [1,n] $,每个点有一个点权 \(p_i\)。
你可以从这 \(n\) 个点中选择任意数量的点。比如说你选的点集合为 \(S\),那么对于每个点 $i \in[1,n] $,如果它左边最接近的(特殊地,不包括自己)被选择的点为 \(L\)(即 $max_{j\in S, j<i} j $ ),右边最接近的(也不包括自己)被选择的点为 \(R\)(即 $min_{j\in S, i<j} j $),那么它将提供 $p_L+p_R $ 的贡献。
正解
很唐啊,很唐。但我没看出来
注意到,相邻的被选择的两点 \(i,j\) 之间这一段的贡献为 $ (p_i+p_j)\times(i-j) $,看起来很像一个矩形。劈一半就是 $ (i,p_i),(j,p_j) $ 两点围成的梯形。由此发现维护凸包直接做即可。复杂度 $ O(n) $。
LL p[N];
LL f[N];
int stk[N],top;
void zako_problem()
{
read(n);
For(i,1,n) read(p[i]);
top=0;
stk[++top]=1;
For(i,2,n){
while(top>1&&(p[i]-p[stk[top]])*(stk[top]-stk[top-1])
>=(p[stk[top]]-p[stk[top-1]])*(i-stk[top])) top--;
int j=stk[top];
f[i]=f[j]+(i-j)*(p[i]+p[j]);
stk[++top]=i;
}
printf("%lld\n",f[n]);
}
但是,真的就只能这样吗?
不妨考虑 dp
手玩一下两项之间插入一个东西会发生什么,得到了一个形如 $ ip_j-jp_i $ 的式子。列一下转移:
定义 \(f_i\) 为转移到 \(i\) 时的原答案,定义 $ g_i=f_i-ip_i $,有转移 $ g_i=max_{j<i} { g_j+ip_j-jp_i } $。
你获得了一个 \(O(n^2)\) 的 dp!
发现斜率
考虑优化。直觉上这个东西其实长得很决策单调性或斜率优化。但是往这些方向想了想感觉不是很对。怎么办呢?
思考一下,究竟何为决策单调性?不论是常规的决策单调性还是斜率优化,都是存在某种支配关系,使得一旦 \(i\) 被使用,那么他将永远支配一堆其他的决策,使其可以被永久删除。
那我们从决策来考虑。
不妨记 \(w(i,j)=jp_i-ip_j\)。
定义 $ T_i(j) $ 表示 \(i\) 从 \(j\) 转移得到的值,即 $ T_i(j)=g_j+w(j,i) $。
加入我们已有对于 \(b\),$a\rightarrow b $ 是最优的,假如说一个 \(c\) 满足了 $ a\rightarrow b\rightarrow c < a\rightarrow c $,考虑发生了什么。
\(g_b=g_a+w(a,b)\)
\(T_c(a)=g_a+w(a,c)\)
\(T_c(b)=g_b+w(b,c)=g_a+w(a,b)+w(b,c)\)
若 \(T_c(a)>T_c(b)>0\),有 \(w(a,c)-w(a,b)-w(b,c)=w(a,c)+w(c,b)+w(b,a)>0\)。
式子展开。
注意到 \((c-b)(b-a)>0\),所以原式即 \((\frac{p_c-p_b}{c-b} > \frac{p_b-p_a}{b-a})\)
经过简单转化,我们发现,这就等价于,一条决策链上满足相邻的 \((i,p_i)\) 斜率递减吗,标准凸包定义。
我们发现,似乎固定 \((i,p_i)\) 后,我们所求就是前面所有 \((j,p_j)(j<i)\) 的点形成的凸包与 \((i,p_i)\) 形成的最小斜率的直线。换句话说,直接拿一条过 \((i,p_i)\) 的直线去切凸包即可。
这也就是我们的广义斜率优化。到此为止可以做到 \(O(n\log n)\) 在凸包上二分斜率找最优决策。
所以,我们,做完了……吗?
等等!这个式子满足仅当 \(a\rightarrow b\),如果不满足这个就不可以了!比如说对于 \(a,b\) 满足 \(x\rightarrow a,y\rightarrow b\),那 \(g_a,g_b\) 将没有任何关系,这个式子也不再适用。
恭喜,我们完蛋啦!
决策结构&永久删除引理
我们都知道,普通的斜率优化有一点决策单调性的影子。那么在本题,能否找到决策单调性呢?
考虑本题中,决策是什么样子的。
定义 \(pre(i)\) 表示 \(i\) 的决策点,不难发现这会形成一个决策树,这对于所有决策类题目是通用的。发现这恰为我们的 $ pre(i) \rightarrow i$ 的连边。为了方便我们仍旧使用 \(\rightarrow\) 表示。
本题中,由于我们只能处理一条“决策链”,即形如 $x_1\rightarrow x_2 \rightarrow x_3 \dots \rightarrow x_k $ 上的点,那我们先考虑一条决策链的变化。
当前正在考虑的点为 \(i\),分讨其决策类型(记 $K(x,y)=\frac{p_x-p_y}{x-y} $):
- 若 \(c\) 的决策点恰为 \(i-1\),那直接将 \(i-1\) 接在后面链尾即可,这是最简单的情况。
- 若 \(i\) 的决策为 \(i-1\) 的一个祖先 \(x\),根据前文的定义,不断往根走,应当有 \(K(i,i-1) > K(i,pre(i)) >\dots > K(i,x)\)。
- 若 \(i\) 的决策不为 \(i-1\) 到根的一条链……那我们真的完蛋了。
但是,这真的可能发生吗?
在决策树上找到 \(x,i-1\) 的最近共同祖先,设为 \(l\)。有 \(l\rightarrow \dots \rightarrow i-1 ,l\rightarrow \dots \rightarrow x\)。不妨尝试简化问题:
拉回前文的 \(a,b,c\) 满足 $a\rightarrow b,a\rightarrow c $。显然 $l,i-1 $ 和 \(l,x\) 之间仍然满足斜率递增的关系,所以可以设 \(a=l\),\(b=x\),\(c=i-1\)。
(大概这样吧,感性理解一下 \(\rightarrow \dots \rightarrow\) 和 \(\rightarrow\) 在斜率的偏序关系上是等价的)
此时决策考虑 \(i\)。若 \(i\) 的决策为 \(b\),那存在 \(K(i,b)<K(i,c)\) 且 \(K(i,b)<K(i,a)\)。
推式子也能推出来这根本不可能,直接画图观察也不难发现这点:\(i\) 可能从 \(a\) 转移,也可能从 \(c\) 转移,但一定不会从 \(b\) 转移。
也就是说如果一个点 \(b\) 被后面的点淘汰掉了,那它将永远不会被作为候选点,\(b\) 就被永久删除了。
换句话说,\((a,c)\) 共同支配 了点 \(b\)。
现在我们可以正式定义共同支配这个概念了:如果存在三个决策 \(i,j,k\) 满足对于任意 \(x\) 均有 $ T_x(j)<T_x(i) \land T_x(j)<T_x(k) = \varnothing $,则称 \((i,k)\) 共同支配了 \(j\)。
当然,如果不感性理解的话,那就将视角调整为“从下往上链的叶子(或者说栈顶)被弹出时,被弹出的点将被共同支配”。
本题中,一旦一个点 \(i\) 的决策指向“当前维护的决策链的非叶结点”,那么它和它的决策 \(pre_i\) 将共同支配原决策链中的 \(pre_i\) 的儿子到原叶子这一串所有的点。
也就是说,对于节点 \(i+1\),至少存在一个可行的最优决策是决策树中 \(i\) 到根节点的链上的点。
Code
int stk[N],top;//我声称这个栈维护的是从根到叶子的链
void zako_problem()
{
read(n);
For(i,1,n) read(p[i]);
top=0;
stk[++top]=1;
For(i,2,n){
while(top>1&&(p[i]-p[stk[top]])*(stk[top]-stk[top-1])
>=(p[stk[top]]-p[stk[top-1]])*(i-stk[top]))
top--;//如果这个叶子不是最优了,就被共同支配了,可以扔了
int j=stk[top];
f[i]=f[j]+(i-j)*(p[i]+p[j]);
stk[++top]=i;
}
printf("%lld\n",f[n]);
}
Q:老大,我们推了这么久,怎么代码和原本的正解完全一样啊?
A:是的,你说得对,这就是原本的代码啊。
Q:那老大,我们想了这么久是白干了吗?
A:你说得对,我们就是白干了!
永久支配引理
既然本题解名字都叫“到永久支配引理”了,那支配这里还是写详细一点吧。
不过说实话,写出来后,我才发现原来我之前其实会的根本不全。还是太菜了啊。
(声明:这里使用了 AI 辅助。辅助方式:这个引理就是和 AI 聊出来的,我让 AI 总结了一下当前对话,并给出一个草稿)
具体地:
约定与声明
决策树:表示由 $pre(i) \rightarrow i $ 形成的外向树。
栈的约定:按编号插入,\(c\) 入栈前维护的是链 \(s_1<\dots<s_k\),相邻两点满足“后一点由前一点转移”,即均有 $s_i\rightarrow s_{i+1},(1\le i\le k-1) $。本引理只处理栈顶相邻的 \(a<b,a=s_{k-1},b=s_k\) 与即将插入的 \(c\)。
引理 1
证明见上文。
引理 2
证明见上文。
引理 3(弦条件)
对 \(a<b<c\),令
\( \lambda =\frac{b-a}{c-a} \in (0,1)\)
记 \(d=p_b-\bigl((1-\lambda )p_a+\lambda p_c \bigr)\),即“ \(b\) 的点比弦 \(ac\) 在 \(b\) 处高出多少”。则以下两件事等价:
- \(d \le 0\),即 \(b\) 在弦 \(ac\) 上或下方;
- \(K(a,b) \le K(b,c)\);
- \(K(a,b) \le K(a,c) \le K(b,c)\)。
数形结合易证
证明:\(d \le 0\) 两边乘 \(c-a>0\):
而 \(K(a,b) \le K(b,c)\) 即 \(\dfrac{p_b-p_a}{b-a} \le \dfrac{p_c-p_b}{c-b}\),两边乘 \((b-a)(c-b)>0\) 并整理,恰好是同一个不等式。第 3 条与第 2 条等价,因为 \(K(a,c)\) 是 \(K(a,b)\) 与 \(K(b,c)\) 的加权平均(\(b\) 在 \(a,c\) 之间)。
引理 4(永久支配引理)
设定:处理 \(c\) 时栈顶为 \(b\),次顶为 \(a\),\(a<b<c\)。则,以下三件事等价:
1. \(b\) 在弦 \(ac\) 下
也即弹栈条件。
2. \(b\) 的决策弱于 \(a\):
即决策点 \(b\) 弱于决策点 \(a\)(但不保证 \(a\) 为最优)。
3. 任意未来查询 \(b\) 均不为严格最优:对每个 \(q>c\),
也就是说,\(b\) 永远不会严格优于 \(a,c\) 两者;删掉 \(b\) 不会改变任何后续答案。
详细证明
引理 2 证明了“\(b\) 在弦 \(ac\) 下”和“\(b\) 的决策弱于 \(a\)”等价。接下来以前者为基础。
\(b\) 由 \(a\) 转移,故
\(c\) 计算 \(g_c\) 时 \(a\) 是合法候选(\(a<c\)),故
第 1 步:作差,消掉 \(p_q\)
由 \(\lambda\) 的定义,\(b=(1-\lambda)a+\lambda c\)。于是
最后一项因为 \(b\) 是 \(a,c\) 的凸组合而整项为 \(0\)。这一步是“对任意 \(q\) 一致”的关键:查询点 \(Q=(q,p_q)\) 只以 \(q\,d\) 的形式出现。
第 2 步:用 (1)(2) 估计方括号
用 \(b-\lambda c=(1-\lambda)a\) 化简:
第 3 步:合并证得任意未来查询
这里用了 \(d \le 0\)(弹栈条件)和 \(q>c>a\),所以 \(q-a>0\)。右边是两个实数的凸组合,自然不超过二者最大值,于是
算法实现的正确性归纳(一段废话)
设处理完 \(i\) 后栈为 \(S_i=(s_1<\dots<s_m=i)\),维护三条不变量:
- (P1) 相邻转移:\(g_{s_{t+1}}=g_{s_t}+w(s_t,s_{t+1})\);
- (P2) 边斜率严格递减:\(K(s_1,s_2)>\dots>K(s_{m-1},s_m)\);
- (P3) 对任意 \(q>i\),\(\max_{j\le i}T_q(j)\) 在 \(S_i\) 上取到(不在栈上的点永远不是唯一最优)。
弹栈合法:\(b\) 被弹时,由引理 4,\(q>c\) 时 \(T_q(b)\le\max(T_q(a),T_q(c))\),而 \(a,c\) 都还在(或同样可继续替换),故 (P3) 不破。
替换链有限:被弹点由当时的 \(a,c\) 支配;若 \(a\) 或 \(c\) 后来也被弹,就用它们被弹时的支配对继续替换。弹出时间严格递增,链必终止于某个仍留在栈上的点,所以“永远”成立。
栈顶就是最优点:弹栈结束时,剩余链满足 \(K(s_{t-1},s_t)>K(s_t,i)\)(或只剩一个点)。归纳可得
因为 \(K(s_{t-1},i)\) 是 \(K(s_{t-1},s_t)\) 与 \(K(s_t,i)\) 的加权平均,而 \(K(s_{t-1},s_t)>K(s_t,s_{t+1})>K(s_t,i)\)。由引理 2,\(T_i(s_1)<\dots<T_i(s_m)\),故栈顶最大;被弹掉的点又都不优于栈顶。于是
启示
这个东西看着很复杂并非看着,但是实际上只有一个核心,就是:
对每个 \(q>c\),存在
这也就是 \(b\) 能被永久删除的原因,也就是永久支配。
所有斜率优化,单调栈单调队列等,能够做到均摊,就是因为每个点只会进出一次。而“只出一次”就是因为一个决策一旦被弹出,就会被候选决策们永久支配。
这给了我们一个新的决策观察方向:我们可以不只看两个决策之间的关系,而是多个决策对单个决策形成的共同支配。
(不过似乎没啥用就是了)
后话
update on 11/4 发布后,朋友提醒:woc坏了,斜率的关系写反了QAQ。对不起!!!
update on 11/5 既然本题解名字都叫“共同支配”了,那共同支配这里还是写详细一点吧。新增了“共同支配引理”这一块。顺便更新了一波 Latex 语法。
说实话,认认真真写(抄)完了这部分才发现,自己之前只懂了个皮毛。AI 大人强强!

浙公网安备 33010602011771号