其他分享
首页 > 其他分享> > 决策单调性优化dp

决策单调性优化dp

作者:互联网

决策单调性优化 \(dp\)

对于转移

\[dp_j=\min_{i<j}(f_i+w(i,j)) \]

令 \(t(i,j)\) 表示从 \(i\) 转移到 \(j\) 后 \(j\) 的 \(dp\) 值

若有对于任意 \(i<j\),存在 \(k\) 使得对于 \(任意d\in[0,k]t(i,d)\le t(j,d)任意d\in[k+1,n]t(i,d)\gt t(j,d)\) 我们就说这个转移具有决策单调性。

容易发现决策单调性具有的性质,决策点单调不减。

如何判断是否满足决策单调性

最常见的方法是证明 \(w\) 满足四边形不等式,及

\[任意p1\leq p2\leq p3\leq p4\\ w(p1,p3)+w(p2,p4)\leq w(p1,p4)+w(p2,p3) \]

可以联想四边形记忆。

下面给出证明

\[若i<j<k_1<k_2\\ 且t(i,k_1)>t(j,k_1)\\ t(i,k_2)\le t(j,k_2)\\ 我们知到\\ w(i,k_1)+w(j,k_2)\le w(i,k_2)+w(j,k_1)\\ 所以可以得到\\ t(i,k_2)+w(i,k_1)+w(j,k_2)\le w(i,k_2)+w(j,k_1)+t(j,k_2)\\ 所以有\\ t(i,k_1)\le t(j,k_1)\\ 与题设相悖 \]

接下来我们考虑如何利用决策单调性优化 \(dp\)。

介绍两种方法,分治法和二分栈

先介绍分治法,分治利用的是决策点的单调性,一般认为有两种情况:

转移来自"上层",\(f\) 为其他已知数列

转移来自"本层",\(f\) 即为 \(dp\).

对于来自上层的处理,我们直接分治处理就可以了。

来自题目

SDOI2016征途

int w(int l,int r){
	return dp[now-1][l]+(a[r]-a[l])*(a[r]-a[l]);
}
void solve(int l,int r,int L,int R){
	if(l>r) return;
	int mid=(l+r)/2;
	int p=L,nw=1e9;
	for(int i=L;i<=R;i++){
		int tmp=w(i,mid);
		if(tmp<nw) p=i,nw=tmp;
	}
	dp[now][mid]=nw;
	solve(l,mid-1,L,p);
	solve(mid+1,r,p,R);
}
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=m;i++){
	now=i;
	solve(1,n,0,n-1);
}
printf("%lld",1ll*dp[m][n]*m-1ll*a[n]*a[n]);

对于来自本层的,我们还需要再嵌套一层分治,且用到定义。

来自题目玩具装箱

void Div(int l,int r,int L,int R){
	if(l>r) return;
	int mid=(l+r)/2;
	int p=L;
	long long nw=1e18;
	for(int i=L;i<=R;i++){
		long long tmp=zy(i,mid);
		if(tmp<nw) nw=tmp,p=i;
	}
	dp[mid]=min(nw,dp[mid]);
	Div(l,mid-1,L,p);
	Div(mid+1,r,p,R);
}
void solve(int l,int r){
	if(l==r) return;
	int mid=(l+r)/2;
	solve(l,mid);
	Div(mid+1,r,l,mid);
	solve(mid+1,r);
}
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
solve(0,n);

二分栈方法,用的是原定义,不需要区分 \(f\) 是否为 \(dp\)。

来自题目玩具装箱

int head=1,tail=0;
qu[++tail]=Node(0,1,n);
for(int i=1;i<=n;i++){
	while(qu[head].r<i) head++;
	dp[i]=zy(qu[head].x,i);
	while(head<=tail&&zy(qu[tail].x,qu[tail].l)>=zy(i,qu[tail].l)) tail--;
	if(head>tail){
		qu[++tail]=Node(i,i+1,n);
		continue;
	}
	int l=max(qu[tail].l,i+1),r=qu[tail].r;
	while(l<=r){
		int mid=(l+r)/2;
		if(zy(qu[tail].x,mid)>=zy(i,mid)) r=mid-1;
		else l=mid+1;
	}
	qu[tail].r=r;
	if(l<=n) qu[++tail]=Node(i,l,n);
}

标签:qu,int,mid,tail,dp,优化,单调
来源: https://www.cnblogs.com/Kamisato-Ayaka/p/16548782.html