1. 程式人生 > >【總結】從詩人小G談DP的四邊形不等式優化

【總結】從詩人小G談DP的四邊形不等式優化

四邊形不等式

w(x,y)w(x,y)是定義在整數集合上的二元函式。若對於定義域上的任何整數,a,b,c,d(abcd)a,b,c,d(a\leq b\leq c\leq d)\existw(a,d)+w(b,c)w(a,c)+w(b,d)w(a,d)+w(b,c)\geq w(a,c)+w(b,d)。則稱函式ww滿足四邊形不等式。

一維DP的決策單調性

對於一維線性狀態轉移方程:
dpi=minj=0i1(dpj+val(j,i))dp_i=min_{j=0}^{i-1}(dp_j+val(j,i))


若函式valval滿足四邊形不等式,則稱dpdp具有決策單調性。

而在bzoj1563詩人小G中,轉移方程如下:
dpidp_i表示前ii句是排版後最小不協排程,lenilen_i為第ii句詩的長度,sumisum_i為前ii句詩的總長度+ii

dpi=minj=0i1(dpj+sumisumj1Lp)dp_i=min_{j=0}^{i-1}(dp_j+|sum_i-sum_j-1-L|^p)

val

(j,i)=sumisumj1Lpval(j,i)=|sum_i-sum_j-1-L|^p,可以按pp奇偶分類求導證明得到:val(j+1,i)+val(j,i+1)val(j,i)+val(j+1,i+1)val(j+1,i)+val(j,i+1)\geq val(j,i)+val(j+1,i+1)(懶,這裡就不具體證明了)

而對於這類決策單調性的線性轉移問題,可以記錄每一個ii所管理的最優決策區間,在具體處理時,用單調佇列儲存三元組(x

,l,r)(x,l,r)(xx表示最優決策點,ll,rr表示其所管理的區間),佇列中按xx升序排列,處理到ii時首先彈出r<ir<i的,然後取隊首更新dpidp_i,彈出隊尾不優的,二分插入即可。

複雜度O(nlogn)O(nlogn)。具體實現可以參照程式碼。

#include<bits/stdc++.h>
using namespace std;
typedef long double ld;
const int N=1e5+10;
const ld nf=1e18;

int n,len,pw,hd,tl,to[N],TK,T,sum[N];
ld dp[N];
char s[N][32];

struct P{
	int st,l,r;
    P(int st_=0,int l_=0,int r_=0):st(st_),l(l_),r(r_){};
}q[N],ori;

inline ld fp(int x)
{
	register ld re=1;
	for(register int i=pw;i;--i) re*=x;
	return re;
}

inline ld cal(int a,int b)
{return dp[a]+fp(abs(sum[b]-sum[a]-1-len));}

inline void sol()
{
	register int i,j,L,R,mid,ans;
	scanf("%d%d%d",&n,&len,&pw);
    for(i=1;i<=n;++i) {
    	scanf("%s",s[i]);
    	sum[i]=sum[i-1]+strlen(s[i])+1;
    }
    hd=tl=0;q[hd]=ori=P(0,1,n);
    for(i=1;i<=n;++i){
    	for(;q[hd].r<i;++hd) q[hd]=ori;
    	to[q[hd].st]=i;dp[i]=cal(q[hd].st,i);
    	for(;cal(i,q[tl].l)<cal(q[tl].st,q[tl].l);--tl) q[tl]=ori;
    	L=q[tl].l;R=q[tl].r;j=q[tl].st;ans=L;
		for(;L<=R;){
    		mid=(L+R)>>1;
    		if(cal(j,mid)<=cal(i,mid)) L=(ans=mid)+1;
    		else R=mid-1;
    	}
    	if(ans<n){
    		q[tl].r=ans;
    		q[++tl]=P(i,ans+1,n);
    	}
    }
    if(dp[n]>nf) puts("Too hard to arrange");
    else printf("%lld\n",(long long)(dp[n]+0.5));
    printf("--------------------\n");
}

int main(){
    hd=0;tl=1;
    scanf("%d",&T);
    for(TK=1;TK<=T;++TK) sol();
    return 0;
}

二維DP的優化

對於區間DPDP中的二維狀態轉移方程:
dp[i][j]=mink=ij1(dp[i][k]+dp[k+1][j]+val(i,j))dp[i][j]=min_{k=i}^{j-1}(dp[i][k]+dp[k+1][j]+val(i,j))
valval滿足四邊形不等式,且對於任意的abcda\leq b\leq c\leq dval(a,d)val(b,c)\exist val(a,d)\geq val(b,c),那麼dpdp也滿足四邊形不等式。(證明要用到數學歸納法)

dp[i][j]dp[i][j]的最優決策為P[i][j]P[i][j]
dpdp滿足四邊形不等式時,對於任意i&lt;ji&lt;jP[i][j1]P[i][j]P[i+1][j]\exist P[i][j-1]\leq P[i][j]\leq P[i+1][j]

而石子合併的DP方程為:
dp[l][r]=mink=lr1(dp[l,k]+dp[k+1][r])+i=lrAidp[l][r]=min_{k=l}^{r-1}(dp[l,k]+dp[k+1][r])+\sum\limits_{i=l}^rA_i

val(l,r)=i=lrAival(l,r)=\sum_{i=l}^rA_i顯然是滿足四邊形不等式的(取到等號),所以求dp[l][r]dp[l][r]時,只需要列舉dp[l][r1]kdp[l+1][r]dp[l][r-1]\leq k\leq dp[l+1][r]即可。
總複雜度為O(i=1n1j=i+1n(P[i+1,j]P[i][j1]+1))=O(i=1n1nn+n)=O(n2)O(\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^n(P[i+1,j]-P[i][j-1]+1))=O(\sum\limits_{i=1}^{n-1}n-n+n)=O(n^2)。原列舉複雜度O(n3)O(n^3)

p.s.
證明什麼的,哪天心情好再補吧。ヾ(◍°∇°◍)ノ゙