【OI】DP-四边形不等式优化

四边形不等式

对于一个代价函数 $w(l,r)$,如果对于任意的 $a\le b\le c\le d$,都满足:

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

则称 $w$ 满足四边形不等式。俗称“交叉小于包含”。

证明 $w$ 满足四边形不等式,等价于证明 $w$ 满足:

w(i,j)+w(i+1,j+1)w(i,j+1)+w(i+1,j)w(i,j)+w(i+1,j+1)\le w(i,j+1)+w(i+1,j)

感性理解即可,这个东西叫 Monge 矩阵

决策单调性

对于一个 DP 转移方程:

fi=min0j<ifj+w(j,i)f_i=\min_{0\le j\lt i} f_j+w(j,i)

其中 $w$ 满足四边形不等式,则 $f$ 满足决策单调性,即:

令 $f_i$ 的最优决策点为 $p_i$(即 $f_{i}$ 由 $j=p_i$ 转移得到),那么对于任意的 $i’\lt i$,都有 $p_{i’}\le p_i$。

可以用反证法证明一下。如果存在 $i_2\lt i_1$,使得 $j_2=p_{i_2}\gt j_1=p_{i_1}$(对于 $i$,$j_1$ 严格优于 $j_2$),也就是如下关系:

此时 $j_1\lt j_2\lt i_2\lt i_1$。那么根据四边形不等式和最优决策点两个性质,可以推出以下三个式子:

w(j1,i2)+w(j2,i1)w(j1,i1)+w(j2,i2)w(j_1,i_2)+w(j_2,i_1)\le w(j_1,i_1)+w(j_2,i_2)
fj1+w(j1,i1)<fj2+w(j2,i1)f_{j_1}+w(j_1,i_1)\lt f_{j_2}+w(j_2,i_1)
fj2+w(j2,i2)<fj1+w(j1,i2)f_{j_2}+w(j_2,i_2)\lt f_{j_1}+w(j_1,i_2)

分别移项得:

w(j2,i1)w(j1,i1)w(j2,i2)w(j1,i2)w(j_2,i_1)-w(j_1,i_1)\le w(j_2,i_2)-w(j_1,i_2)
fj1fj2<w(j2,i1)w(j1,i1)f_{j_1}-f_{j_2}\lt w(j_2,i_1)-w(j_1,i_1)
w(j2,i2)w(j1,i2)<fj1fj2w(j_2,i_2)-w(j_1,i_2)\lt f_{j_1}-f_{j_2}

合并一下就推出 $f_{j_1}-f_{j_2}\lt f_{j_1}-f_{j_2}$,显然是不对的,所以假设不成立,原命题得证。

四边形不等式优化 DP

模板题

首先我们可以写出最朴素的 DP,定义 $f_{k,i}$ 表示前 $i$ 个人分 $k$ 段的总代价的最小值,则有如下转移:

fk,i=min0j<ifk1,j+w(j,i)f_{k,i}=\min_{0\le j\lt i} f_{k-1,j} + w(j,i)

其中 $w(j,i)$ 表示将区间 $(j,i]$ 中的人分成一段的代价,显然可以用 $a$ 的二维前缀数组 $s$ 表示:

w(j,i)=si,isi,jsj,i+sj,jw(j,i)=s_{i,i}-s_{i,j}-s_{j,i}+s_{j,j}

$w$ 是满足四边形不等式的:一大段人分成一段,肯定不如拆成两段,进而推得四边形不等式。

因此 $f_k$ 具有决策单调性

这有什么用呢?这显然有用。我们可以在转移过程中用双端队列维护每个位置的最优决策点 $j$,最优决策点相同的位置合并成一个区间 $[l,r]$ 塞进队列,大概如下:

对于 $i$,我们可以从队头取出其对应的最优决策点,计算答案。然后更新后面的最优决策点,具体过程如下:

因为有决策单调性,所以目前以 $i$ 为最优决策点的位置一定是序列的一个后缀。我们每次从队尾取出一个区间 $[l,r]$,其原最优决策点为 $j$,如果现在 $i$ 转移到 $l$ 优于 $j$ 转移到 $l$,则将这段出队;否则,有可能这段里的某个后缀的最优决策点均为 $i$,我们需要二分出分界点 $x$,满足 $[l,x)$ 的最优决策点为 $j$,$[x,r]$ 的最优决策点为 $i$,然后将新的段放入队列,停止循环。

代码
C++
using vi=vector<int>;

vector<vi>f(m+1,vi(n+1));
struct S{int l,r,j;};
deque<S>q;
q.eb(S{1,n,0});
auto W=[&](int j,int i){return (s[i][i]-s[i][j]-s[j][i]+s[j][j])/2;};
auto func=[&](int k,int i,int j){return f[k][j]+W(j,i);};
for(int k=1;k<=m;k++){
    deque<S>q2;
    q2.eb(S{1,n,0});
    for(int i=1;i<=n;i++){
        while(!q.empty()&&q.front().r<i)q.pop_front();
        assert(!q.empty());
        f[k][i]=func(k-1,i,q.front().j);
        while(!q2.empty()&&func(k,q2.back().l,q2.back().j)>=func(k,q2.back().l,i))q2.pop_back();
        int sc=i+1;
        if(!q2.empty()){
            S nd=q2.back();q2.pop_back();
            int l=nd.l,r=nd.r,mid;//二分分界点
            sc=r+1;
            while(l<=r){
                mid=(l+r)/2;
                if(func(k,mid,nd.j)>=func(k,mid,i))r=mid-1,sc=mid;
                else l=mid+1;
            }
            if(sc!=nd.l)q2.eb(S{nd.l,sc-1,nd.j});
        }
        if(sc!=n+1)q2.eb(S{sc,n,i});
    }
    q=q2;
}
cout<<f[m][n]<<endl;

模板题2

依旧先写出最朴素的 DP,设 $f_i$ 表示只考虑前 $i$ 句的最小代价,则有如下转移:

fi=min0j<ifj+w(j,i)f_i=\min_{0\le j\lt i} f_j + w(j,i)

其中 $w(j,i)$ 可以用句子长度的前缀和 $s_i=\sum_{k=1}^{i}\text{len}_k$ 表示:

w(j,i)=|(si+i)(sj+j+1+L)|Pw(j,i)=|(s_i+i)-(s_j+j+1+L)|^P

感性理解一下这玩意儿满足四边形不等式即可(其实是我还没学会怎么证),后面的就跟上一题一样了。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇