「Note」DP 方向 - DP 优化

1. 单调队列优化 DP

1.1. 简介

当一个选手比你小还比你强,你就打不过他了。这是对单调队列简单形象的概括。

单调队列在转移的过程中不断排除不可能成为决策点的元素,使每次转移寻找决策点的时间复杂度降为 O(1)。一般地,可被单调队列优化的转移式可被写为如下形式:

Fi=maxlij<i{Fj+Aj+Bi}

Fi=minlij<i{Fj+Aj+Bi}

其中需要满足 li 单调不降Ai 是只与 i 有关的变量,Bj 是只与 j 有关的变量。

不难发现单调队列要维护的是 Fi+Ai,每次 j1 入队时,若满足 Fj1+Aj1>Fj0+Aj0 则将 j0 弹出,直到不满足条件或者队列为空。

此时取队头元素,它一定满足在范围内最优,将其作为决策点即可。特殊地,有时需要特判队列为空的情况。

1.2. 常见技巧

大部分情况下,转移方程并不显著,因为在其中的贡献往往与 i,j 都有关,此时尝试将贡献转化为 Aj+Bi 的形式,然后在单调队列中维护 Fi+Ai 即可。

1.3. 例题

P1776(单调队列优化多重背包)

vi wi ci Fi,j
物品 i 的体积 物品 i 的价值 物品 i 的个数 i 个物品放入总体积为 j 的物品的最大价值

显著地,有以下转移方程:

Fi,j=max0kci  k×vij{Fi1,jk×vi+k×wi}

j=jk×vi,在保证 i 不变的情况下,分别考虑每个 jj 的贡献,此时有 k=jjvi。此时 j,jmodvi 的意义下同余,设 j=t×vi+r 其中 0r<vi,考虑将贡献拆分有 j=jk×vi,k=jvijvi=tjvi,将原方程改写:

Fi,j=max0kmin{ci,t}{Fi1,jk×vijvi×wi}+t×wi

不难想到在枚举 r 的基础上,枚举 j 进行单调队列优化。

Code
#define LL long long
#define UN unsigned
#include<bits/stdc++.h>
using namespace std;
//--------------------//
const int N=1e5+1;

int n,V;
int v[N],w[N],c[N];

int ans,f[N];

int head,tail;
int q[N][2];
//--------------------//
int main()
{
    scanf("%d%d",&n,&V);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&w[i],&v[i],&c[i]);
    for(int i=1;i<=n;i++)
        for(int r=0;r<v[i];r++)
        {
            head=tail=1;
            q[1][0]=r,q[1][1]=f[r];
            for(int tem,t,j=r+v[i];j<=V;j+=v[i])
            {
                tem=f[j]-j/v[i]*w[i],t=j/v[i];
                while(head<=tail&&q[head][0]<j-c[i]*v[i])
                    head++;
                f[j]=max(f[j],q[head][1]+t*w[i]);
                while(head<=tail&&q[tail][1]<tem)
                    tail--;
                q[++tail][0]=j,q[tail][1]=tem;
            }
        }
    for(int i=1;i<=V;i++)
        ans=max(ans,f[i]);
    printf("%d",ans);
    return 0;
}

P3089

xi pi Fi,j nowi
目标点 i 的坐标 目标点 i 的分数 跳至目标点 i,上一个目标点是 j ,所能获得的最大分数 当前单调队列还未加入的最近位置

先考虑单方向的做法,显著地,按照 xi 排序后有以下转移方程:

Fi,j=maxxixjxjxk{Fj,k}+pi

我们发现当 i 固定时并不能直接用单调队列优化,因为维护的 max 中存在两个不固定值 j,k。考虑固定 j,当 i 上升时,k 的范围单调不减,此时可以用单调队列维护。

对于每一个 j 维护一个单调队列,用 nowj 记录还未进队的最近位置,每次枚举 i 时,将符合条件的 k 入队,并更新 nowj

至于向另一方向跳的情况,将数轴左右翻转再做一遍 DP 即可。

P4544

ka e xi ci vi fi,j
需要饲料总数 中点坐标 商店 i 坐标 商店 i 库存 商店 i 价格 走到商店 i 经过交易后得到 j 个饲料的最小消费

先按照 xi 排序,显著地,转移方程:

Fi,j=minjcik<j{fi1,k+(xixi1)×k2+(jk)×vi}

将其转化:

Fi,j=minjcik<j{fi1,k+(xixi1)×k2+k×vi}+j×vi

显著的单调队列。其中需要注意的是初值的设置以及转移的始末位置。

x. 前置知识 决策单调性

x.1. 简介

决策单调性是一个优秀的性质,对于具有决策单调性的动态规划可以采用很多方法进行优化。

通常地,决策单调性体现在 1D 维度上。当 j<j<i<i 时,若 FiFj 转移过来,那么 Fi 不可能从 Fj 转移过来,只可能从 Fj 或之后的状态转移。这种性质可称之为决策单调性。

x.2. 四边形不等式

四边形不等式如下,在 a<b<c<d 的情况下 w(a,d)+w(b,c)>w(a,c)+w(b,d)

FiFj+w(i,j) 转移来,若满足四边形不等式则称其具有决策单调性。

证明略,待施工。

2. 斜率优化

2.1. 简介

当一个最优化 DP 的转移方程形如:

Fi=min{Fj+Ai+Bj+ai×bj}

(Fi=max{Fj+Ai+Bj+ai×bj})

即其中有一些只关于 i,j 其中一个的项和一个关于 i,j 两个变量的项,可以考虑用斜率优化来解决。

先对原式进行化简。设 FiFj 转移过来,有 Fi=Fj+Ai+Bj+ai×bj,移项得:

Fj+Bj=ai×bj+(FiAi)

y=Fj+Bj,x=bj,k=ai,b=AiFi,当 i 固定时,我们得到了一个 k 固定的一次函数,使其经过不同的 (x,y)(与 j 有关),可以得到不同的截距 b(与 Fi 有关),其中取截距最大或最小,可以得到 Fi 的最大或最小值,因题而异。

具体地,我们维护一个凸包,取一次函数与切点为决策点。

2.2. 常见技巧

posted @   Eon_Sky  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示