四边形不等式优化dp 学习笔记

对于 \(f_i\) ,有:

\[f_i=\min_{j=1}^{i} f_{j-1}+w(j,i) \]

其中 \(w(j,i)\) 为区间 \([j,i]\) 的权值,\(w(i,j)\) 的值不会改变。记 \(K_i\)
\(i\) 的最优决策点,也就有 \(f_i=f_{K_i-1}+w(K_i,i)\)

如果 \(w(i,j)\) 满足四边形不等式,则有 \(\forall i\in[1,n-1]\),有 \(K_i\le K_{i+1}\),也就是有 \(K_1\le K_2\le ...\le K_n\),这样就具有 决策单调性

四边形不等式

对于 \(a\le b\le c\le d\),有

\[w(a,c)+w(b,d)\le w(a,d)+w(b,c) \]

也就是 相交 \(\le\) 包含

注:若表达式为取 \(\max\) 的话会反过来,也就是相交 \(\ge\) 包含。其实总结一下,就是 相交优于包含

更常见的形式是,对于 \(i\le i+1\le j-1\le j\),有

\[w(i+1,j)+w(i,j-1)\le w(i,j)+w(i+1,j-1) \]

或者写成差分形式,为

\[w(i+1,j)-w(i+1,j-1)\le w(i,j)-w(i,j-1) \]

这样就方便证明 \(w(i,j)\) 满足四边形不等式。


为什么满足四边形不等式就有决策单调性?

证明:

考虑反证。假设存在 \(i<j\) 满足 \(K_i>K_j\)

因为有取 \(\min\),根据最优性,一定有:

\[dp_{K_i-1}+w(K_i,i)\le dp_{K_j-1}+w(K_j,i)\\ dp_{K_j-1}+w(K_j,j)\le dp_{K_i-1}+w(K_i,j)\]

两式相加,则有:

\[dp_{K_i-1}+w(K_i,i)+dp_{K_j-1}+w(K_j,j)\le dp_{K_j-1}+w(K_j,i)+dp_{K_i-1}+w(K_i,j) \]

左右两边同时减去 \(dp_{K_i-1}+dp_{K_j-1}\) ,则有:

\[w(K_i,i)+w(K_j,j)\le w(K_j,i)+w(K_i,j) \]

而又因为有 \(K_j<K_i\le i<j\)\(w(i,j)\) 满足四边形不等式。所以代入 \(K_j,K_i,i,j\) 则有:

\[w(K_j,i)+w(K_i,j)\le w(K_j,i)+w(K_j,j) \]

那么上下两个不等式都成立当且仅当中间取等号,那么就有 \(K_i=K_j\),不符合 \(K_i>K_j\)。所以上述两个不等式相互矛盾,假设不成立。

得证。


对于决策单调性的题目,通常有两种实现方式。

实现方式1:分治

需要满足转移跟枚举的顺序无关

就如有转移式

\[f_i=\min_{j=1}^{i} g_{j-1}+w(j,i) \]

此处 \(g\) 数组的值已知。那么就可以用分治实现。

对于任意区间 \([l,r]\),设 \(mid=\lfloor\frac{l+r}{2}\rfloor\)

首先对于 \([1,n]\) ,我们可以先求出 \(K_{mid}\) 的值。我们知道 \(1\le K_{mid}\le n\),所以可以枚举 \([1,n]\),再取最小的为 \(K_{mid}\)

现在要分治下去了。

  • 那么对于 \(\forall i\in[1,mid-1]\) ,一定有 \(1\le K_i\le K_{mid}\),所以在 \([1,K_{mid}]\) 里找新的 \(K\) 值。

  • 而对于 \(\forall i\in[mid+1,n]\),一定有 \(K_{mid}\le K_i\le n\),在 \([K_{mid},n]\) 里找新的 \(K\) 值。以此递归。

所以抽象地说。对于区间 \([l,r]\),在 $[K_{l-1},K_{r+1}] $ 里找到最小的转移值,最小转移值对应位置则为 \(K_{mid}\)。然后再分治下去。

初始的时候可以让 \(K_0=1,K_{n+1}=n\)

单次一维dp时间复杂度 \(O(n\log n)\)

参考代码:

k[0]=1,k[n+1]=n;
void div(int l,int r,int j)
{
	if(l>r) return;
	int L=k[l-1],R=k[r+1],mid=(l+r)>>1;
	for(int i=L;i<=R;i++)//更新 k[mid] 的值 
	{
		if(w(i,mid)+g[i]<dp[mid]) 
		{
			dp[mid]=w(i,mid)+g[i];
			k[mid]=i;
		}
	}
	div(l,mid-1,j),div(mid+1,r,j);//分治下去 
}

同样,对于转移式如下的二维dp也可以这样搞:

\[dp_{k,i}=\min_{j=1}^i dp_{k-1,j-1}+w(j,i) \]

因为 \(dp_{k-1,j}\) 是已知的了。

实现方式2:二分+双端队列

那么什么情况不能用分治?就如开篇的第一个转移式:

\[f_i=\min_{j=1}^{i} f_{j-1}+w(j,i) \]

如果先去更新 \(f_{mid}\) ,连 \(f_{0\sim mid-1}\) 的值都不知道怎么判断哪个是最优决策点?

所以现在要考虑另一种方法了。

因为必须顺序枚举,考虑动态更新维护 \(K\) 值。

初始时, \(K=\{1,1,...,1\}\)。现在我们已经求出 \(f_1\) 的值了,对应的 \(j\)\(2\)。那我们就去二分找最小的位置满足这个点用 \(2\) 转移比用 \(1\) 转移更优。根据决策单调性,那么它后面的所有位置用 \(2\) 转移都更优。所以 \(K=\{1,1,1,...,1,2,2,2,...,2\}\)

然后就不断去计算 \(f_{j-1}\),然后二分更新后面的 \(K\) 值。

现在涉及到一个区间覆盖问题。可以珂朵莉树,可以线段树,但是太麻烦了。能不能更简单一点?

我们发现,任何时候一种 \(K\) 值都是在一段里的。所以考虑用队列依次记录下每一种 \(K\) 值。同时,开一个数组 \(pos_i\)\(K_j=i\) 的最小的 \(j\),也就是 \(i\) 这种 \(K\) 值最前面的位置。

现在考虑更新了。因为可能存在更新完后,某几种 \(K\) 值就不存在了。所以考虑从队尾开始,依次判断队尾 \(K\) 值的第一个位置用新 \(K\) 值转移是否更优。如果更优那么直接弹出队尾,因为这种 \(K\) 值会被完全覆盖掉从而消失。

直到找到第一个不满足要求的为止。设该不满足要求的 \(K\) 值为 \(x\)。则 \(x\) 不会被完全覆盖,且覆盖的始端是在 \(pos_x\) 以后。所以再在 \((pos_x,n]\) 中二分找覆盖的始点,将新 \(K\) 值的 \(pos\) 更新为这个点的下标,然后将这个 \(K\) 值放入队尾。

然后是单点查 \(K_i\)。因为 \(i\) 是单增的。所以当队首的后一个 \(K\) 值的 \(pos\)\(\le i\) 时则弹出队首。然后最终的队首就是 \(K_i\)

时间复杂度 \(O(n\log n)\)。该方法适用范围比较广泛。

参考代码:

int sum(int a,int b)
{
	return dp[a-1]+w(a,b);//从a转移到b的转移值 
}
void dp()
{
	hd=tl=1;
	q[tl]=1;
	for(int i=1;i<=n;i++)
	{
		while(hd<tl&&pos[q[hd+1]]<=r) hd++;
		int k=q[hd];
		dp[i]=sum(k,i);//查询 
		
		while(hd<tl&&sum(r+1,pos[q[tl]])<sum(q[tl],pos[q[tl]])) tl--;//如果被完全覆盖则删去 
		int l=max(i,pos[q[tl]])+1,r=n,ans=n+1;
		while(l<=r)//二分答案找覆盖的范围 
		{
			int mid=(l+r)>>1;
			if(sum(i+1,mid)<sum(q[tl],mid)) r=mid-1,ans=mid;
			else l=mid+1;
		}//更新 
		pos[i+1]=ans;
		q[++tl]=i+1;
	}
}

因为码量会稍微大一点且常数会大一点,所以能写分治还是习惯写分治。


练习题:

  1. P1880 [NOI1995] 石子合并 \(O(n^2)\) 四边形不等式优化区间dp

  2. P1912 [NOI2009] 诗人小G

  3. P4767 [IOI 2000] 邮局 加强版 可以写分治实现

    P6246 [IOI 2000] 邮局 加强版 加强版 需要加wqs二分,不能写分治实现

  4. CF2073K Book Sorting 贪心+决策单调性,题解

posted @ 2025-02-07 19:06  Twilight_star  阅读(59)  评论(0)    收藏  举报