学习笔记——四边形不等式

前言#

模拟赛出四边形不等式部分分了!被我用暴力艹过了这一档部分分!

注意!文中的式子都是用了取 min 作为转移,如果是 max 也是一样的。细节会有所区别。

四边形不等式#

定义#

对于一个二元函数 w(a,b)

abcd,都有 w(a,d)+w(b,c)w(a,c)+w(b,d)

则称这个二元函数满足四边形不等式。

也就是市面上常说的:包含大于交叉

基本判定定理#

如果 w(a,b) 满足对任意 a<b,都有 w(a,b+1)+w(a+1,b)w(a,b)+w(a+1,b+1),则 w(a,b) 满足四边形不等式。

挺显然又好证(数归),那证明就略吧。

决策单调性优化动态规划#

四边形不等式不过是一个用来证明决策单调性的工具。而决策单调性才是对 dp 进行优化的关键。

1D1D 单调优化#

四边形不等式可以用来优化对于形式如:

dpi=min0j<i{dpj+w(j,i)}

的转移式子,如果其中 w(a,b) 是满足四边形不等式的,那么这个 dp 就满足决策单调性

Proof

我们采用反证法:

假如当前有 a<b<c<d,其中 bc 的最优决策点,假如 a 会是 d 的最优决策点,那么有:

dpb+w(b,d)dpa+w(a,d)

但是根据四边形不等式,我们有:

w(a,d)+w(b,c)w(a,c)+w(b,d)

将两式相加,消去同类项后得到:

dpb+w(b,c)dpa+w(a,c)

也就是对于 c 而言,a 将会是更优的决策点,这与假设:bc 的最优决策点相矛盾。故 a 不会是 d 的最优转移点。

我们利用它的单调性,维护一个决策点数组 p。容易发现,p 一定是由若干段连续的相同元素构成的。然后我们在更新了 i 之后,考虑更新它之后的 p,不难想到一定是更新一段后缀,所以我们只要找到这个分界点,后面用 i 作决策点更优,而前面用原来的 p 是更优的。这个东西可以二分。

实现的时候,我们用队列中存三元组的方式来代替直接维护整个 p。具体地,三元组 (l,r,p) 表示 [l,r] 中每个位置的当前最优决策点是 p,然后把 p 数组从前往后这样压缩起来。这样在更新 i 的时候,从队头找到第一个包含 i 的(不包含可以直接弹出了),直接 O(1) 转移。然后用 i 来更新后面的 p 数组,就是从队尾一个一个弹出,如果对于当前三元组 (l,r,p),对 l 来说决策点 p 劣于 i,说明整个都是 i 来转移更优,那就直接弹出;否则,我们在 [l,r] 之间二分找到那个分界点,然后修改队尾的 r,并压入 (ans,n,i),其中 ans 是第一个以 i 为最优决策点的点(也就是你二分得到的),然后结束。

我的叉点
  1. 二分注意细节,不要写错;
  2. 最后得到二分结果 ans 之后,需要判断 ans 是否大于 n,否则会在之后从队尾遇到它然后产生一些错误。

例题

我们有 w(a,b)=abs(prebpreaL+ba1)P,满足四边形不等式,直接用上面说的优化就可以了。

My Code
const int MAXN=1e5+10;
const ll MAX=1e18;
long double pre[MAXN],dp[MAXN],L;
int P;
long double w(int l,int r){
	long double ret=abs(pre[r]-pre[l]-L+r-l-1),v=1;
	rep(i,1,P) v*=ret;return v;
}
struct RG{int l,r,p;};
string s[MAXN];
int p[MAXN];
void print(int i){
	if(p[i]) print(p[i]);
	rep(j,p[i]+1,i) cout<<s[j]<<" \n"[j==i];
}
void solve(){
	int n;cin>>n>>L>>P;
	rep(i,1,n) cin>>s[i],pre[i]=pre[i-1]+s[i].size();
	deque<RG> q;q.push_back(RG{1,n,0});
	rep(i,1,n){
		while(!q.empty()&&(q.front().r<i||q.front().l>q.front().r)) q.pop_front();
		p[i]=q.front().p;dp[i]=dp[p[i]]+w(p[i],i);q.front().l=i;
		while(!q.empty()&&dp[q.back().p]+w(q.back().p,q.back().l)>=dp[i]+w(i,q.back().l))
			q.pop_back();
		if(q.empty()){
			q.push_back(RG{i,n,i});
			continue;
		}
		int l=q.back().l,r=q.back().r,pp=q.back().p,ans=r+1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(dp[pp]+w(pp,mid)>=dp[i]+w(i,mid))
				r=mid-1,ans=mid;
			else l=mid+1;
		}
		q.back().r=ans-1;
		if(ans<=n) q.push_back(RG{ans,n,i});
	}
	if(dp[n]>MAX) cout<<"Too hard to arrange\n";
	else cout<<(ll)dp[n]<<'\n',print(n);
	cout<<"--------------------\n";
	while(!q.empty()) q.pop_back();
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;for(cin>>T;T--;)
		solve();
	return 0;
}

2D1D 分层转移优化#

这种题一般具有相邻层之间转移的特征。并且同一层转移的时候具有决策单调性。这个单调性,我们同样是看 w(a,b) 是否满足四边形不等式。比如说,在我们 1D1D 优化的基础上,规定分成恰好 k 段,这样就变成了:

dpd,i=min0j<i{dpd1,j+w(j,i)}

此时,我们发现与 1D1D 优化不同的是,我们在求某一层的时候,上一层的答案已经求好了,并且在当前层具有决策单调性。那考虑递归分治来 dp。即令 DP(l,r,p,q) 表示在求 lr 一段的 dp 值时,最优决策点在 pq 一段。然后我们求 mid=l+r2,并暴力枚举找出 mid 的最优决策点。然后根据决策单调性,分治往下做。这样复杂度是 O(nlogn) 每层,共 k 层,故复杂度优化为 O(nklogn)

例题

看到这题容易想到枚举每个邮局控制哪段区间,就发现转移式子和上面说的是一样的。好现在我们只需要考虑 w(a,b) 是否满足四边形不等式就可以了。

首先,w(a,b) 的含义是,ab 一段内放置一个邮局,使得 ab 的所有村庄到这个邮局的最小距离和。不难发现,邮局一定是放在中位数的地方——如果是奇数个村庄,就放最中间的村庄处;否则就放最中间两个村庄的中间。

然后你发现这个东西是满足四边形不等式的,可以用上述优化。可惜的是,每次暴力求 w(a,b) 复杂度不够优秀。但是容易发现,这个东西可以递推。初始的时候 w(a,a)=0,然后 w(a,b)=w(a+1,b)+da+ba+12da 实现转移。

这样转移就是:

dpd,i=min0j<i{dpd1,j+w(j+1,i)}

递归分治优化即可。

My Code
const int MAXN=3010;
int w[MAXN][MAXN],d[MAXN],V,P;
int dp[MAXN][MAXN];
void DP(int D,int l,int r,int p,int q){
	if(l>r) return;
	int mid=(l+r)>>1,k=p,mx=dp[D-1][k]+w[k+1][mid];
	rep(i,p+1,min(q,mid-1)){
		if(dp[D-1][i]+w[i+1][mid]<mx)
			mx=dp[D-1][i]+w[i+1][mid],k=i;
	}dp[D][mid]=mx;
	DP(D,l,mid-1,p,k);DP(D,mid+1,r,k,q);
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>V>>P;
	rep(i,1,V) cin>>d[i];
	rep(len,2,V) for(int l=1;l+len-1<=V;l++){
		int r=l+len-1;
		w[l][r]=w[l+1][r]+d[l+(r-l+1)/2]-d[l];
	}
	rep(i,1,V) dp[0][i]=INF;
	rep(D,1,P) DP(D,1,V,0,V);
	cout<<dp[P][V]<<'\n';
	return 0;
}

四边形不等式对区间 dp 的优化#

个人认为这不属于决策单调性的范畴,但是也是四边形不等式的重要运用之一。

区间 dp 的转移通常形如:

dpl,r=mink[l,r){dpl,k+dpk+1,r}+w(l,r)

我们暂时称之『区间转移式』。

区间包含单调性#

为了对区间 dp 进行优化,我们需要提出这个新的概念。区间包含单调性,即对于一个二元函数 w(a,b),对于 abcd,满足 w(a,d)w(b,c),即包含大于被包含,就称这个二元函数具有区间包含单调性。

定理#

如果对于一个区间转移式,满足:

  1. w(a,b) 满足四边形不等式;
  2. w(a,b) 具有区间包含单调性;
  3. 有边界 w(a,a)=dpa,a=0

则有 dpl,r 满足四边形不等式。

Proof

采用数学归纳法。

i+1=j 时,dpi,j+1+dpi+1,j=dpi,i+2+dpi+1,i+1=dpi,i+2

我们采用基本判定定理,要证 dpl,r 满足四边形不等式,我们只要证明 dpi,j+1+dpi+1,jdpi+1,j+1+dpi,j。下面进行分讨:

  • 如果对 dpi,i+2 来说,最优决策点在 idpi,i+2=dpi,i+dpi+1,i+2+w(i,i+2)=w(i+1,i+2)+w(i,i+2)w(i+1,i+2)+w(i,i+1)=dpi+1,i+2+dpi,i+1=dpi+1,j+1+dpi,j。即:dpi,j+1+dpi+1,jdpi+1,j+1+dpi,j
  • 如果对 dpi,i+2 来说,最优决策点在 i+1dpi,i+2=dpi,i+1+dpi+2,i+2+w(i,i+2)=w(i,i+1)+w(i,i+2)w(i,i+1)+w(i+1,i+2)=dpi+1,i+2+dpi,i+1=dpi+1,j+1+dpi,j。即:dpi,j+1+dpi+1,jdpi+1,j+1+dpi,j

综上,当 i+1=j 时,上述定理成立。

接下来进行归纳。若对于 i+k>j 时,该定理成立,则证明当 i+k=j 时成立:

dpi+1,j 的最优决策点为 xdpi,j+1 的最优决策点为 y,必然有 xy。此时有:

dpi+1,j+dpi,j+1=dpi+1,x+dpx+1,j+w(i+1,j)+dpi,y+dpy+1,j+1+w(i,j+1)

而对于 dpi,jdpi+1,j+1 来说,这两个点必然分别是决策点之一,但不一定最优,故有:

dpi,j+dpi+1,j+1dpi,x+dpx+1,j+w(i,j)+dpi+1,y+dpy+1,j+1+w(i+1,j+1)

然后根据 w(a,b) 有四边形不等式以及在 i+k>j 时,dpi,j 满足四边形不等式,有:

w(i,j+1)+w(i+1,j)w(i,j)+w(i+1,j+1)dpi+1,x+dpi,ydpi,x+dpi+1,y

代入上面推出的式子,得到 dpi+1,j+dpi,j+1dpi,j+dpi+1,j+1

单调性#

我们记 Pi,jdpi,j 的最优决策点。则有结论:

Pi,j1Pi,jPi+1,j

Proof

我们记 p=Pi,j,则 k(i,p],有(已经证明 dpi,j 满足四边形不等式):

dpi,p+dpi+1,kdpi,k+dpi+1,p

移项,得到:

dpi+1,kdpi+1,pdpi,kdpi,p

p=Pi,j,则有:

dpi,k+dpk+1,jdpi,p+dpp+1,j

然后将两式相加,移项,得到:

dpi+1,k+dpk+1,jdpi+1,p+dpp+1,j

两边同时加上 w(i+1,j),不难发现这就是对于 dpi+1,j 的两个决策点的转移式。并且我们发现,p 转移时更优的,也就是说,对于所有的 kp,都不如用 p 转移更优,所以有 Pi+1,jp=Pi,j

同理可以证明 Pi,jPi,j1

应用#

接下来我们运用这个单调性来优化区间 dp。

不难发现,在跑区间 dp 的时候,对于 dpi,jPi,j1Pi+1,j 都是已经求出的,我们只要在这个区间内枚举决策点就可以了。

容易证明复杂度为 O(n2)

方便地证明四边形不等式#

为了让你能够看出某个二元函数满足四边形不等式,整理如下性质(摘自 oi-wiki):

  1. w1(a,b),w2(a,b) 均满足四边形不等式(或区间包含单调性),则对于任意 c1,c20,函数 w(a,b)=c1w1(a,b)+c2w2(a,b) 也满足四边形不等式(或区间包含单调性)。
  2. 若存在函数 f(x),g(x) 使得 w(l,r)=f(r)g(l),则函数 w 满足四边形不等式。当函数 f,g 单调递增时,函数 w 还满足区间包含单调性。
  3. h(x) 是一个下凸的增函数,w(a,b) 满足四边形不等式和区间包含单调性,则 h(w(a,b)) 也满足四边形不等式和区间包含单调性。
  4. h(x) 是一个下凸的函数,w(a,b) 满足四边形不等式和区间包含单调性,则 h(w(a,b)) 满足四边形不等式。

练习#

一些奇怪的优化 trick 可能会出现在这里。

主要找的是决策单调性优化的题目。

现在有 n 个人,连续的若干人可以分为一组,你要分成 k 组,使得每一组的权值和最小。定义一组人的权值为 i[1,m]j[i+1,m]ui,j,其中 m 为当前组人的个数。u 为给定的 n×n 的矩阵。

Solution

感觉这种分组题就大概率是可以用四边形不等式优化的。

首先,我们考虑 w(i,j) 是什么。容易发现,就是 u 中横纵坐标都在 [i,j] 中的所有数的和的一半。这个一半可以最后再说,所以我们直接对 u 求二维前缀和。这样就有:w(i,j)=uj,jui1,juj,i1+ui1,i1,显然满足四边形不等式。

然后你发现这题可以直接套用上面邮局的做法,然后你就做完了。

给你一个长度为 n 的序列,你要把它分成连续 k 组,使得每一组的权值和最小。一组数的权值定义为这一段中逆序对的个数。

Solution

还是非常显然的转移。然后你考虑逆序对个数是否满足四边形不等式。满足吗?满足啊!然后还是一样套个板子就写完了/qd。然后你还需要用树状数组来预处理区间逆序对的个数。

后记#

能用的题好少啊,大多数都涉及到凸优化啊以及一些 wqs 二分。或者就是能用斜率优化直接艹。

那下次去学学 wqs 二分吧/qd。


  1. 指一阶导函数单调递增的函数。 ↩︎

posted @   ZCETHAN  阅读(296)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示
主题色彩