【整理】算法竞赛动态规划学习笔记

一些动态规划类型

树形 DP

树形 dp 的常用方法(例如树上背包)是将接下来要处理的儿子与以及处理完的儿子的全体进行合并,即把处理多个子树的问题转换为依次合并两个儿子的问题。

树形 dp 类型众多,故这里不多做赘述。

状压 DP

状压 dp 的核心是把状态用二进制数进行压缩(有些时候可能会用到四进制,如果一个点有三种或四种状态)。处理状压 dp 的核心是如何尽可能简洁地表示出当前状态,以及如何进行状态的转移。

例题:

[NOI2001]炮兵阵地

郊区春游

这两题都是模板提,状态的表示比较容易,分别用 0/1 表示 无/有 即可。

Mondriaan’s Dream

这一题的难度则较大。对于每一个点看似有三个状态,但是三进制表示的状态数是过多的,我们需要想办法将其中两种状态合成一种状态进行表示,同时又做到不重不漏且可以转移。

数位 DP

数位 dp 是一类计数问题,形如统计区间 $[l,r]$ 内有多少数满足某条件。数位 dp 是有模板可用的,本质是利用了记忆化搜索的思想,核心是通过状态的设计使得可能的状态数尽可能,而状态如何设计与题目所要求的内容息息相关。

下面是数位 dp 的模板:

ll dfs(int pos,int status,bool flag){
    //status 记录当前状态,根据题目来定,有时也需要用两个变量来记录
    //flag 表示当前是否受到最大位限制(flag=1 -> 不受限)
    if(pos==0) return 1;//这里表示遍历完后的返回值,根据题目变更
    if(flag&&f[pos][status]!=-1) return f[pos][status];
    int maxi=flag?9:a[pos];
    ll ans=0;
    for(int i=0;i<=maxi;i++){
        ans=(ans+dfs(pos-1,,flag || (i<maxi)))%mod;//这里的状态转移要根据题目来写
    }
    if(flag) f[pos][status]=ans;
    return ans;
}
//以下内容在主函数中使用
memset(f,-1,sizeof(f));
int cnt=0;
while(r){
    a[++cnt]=r%10;
    r/=10;
}
ll ans=dfs(cnt,,0);
cnt=0;
if(l!=0){
    l--;
    while(l){
        a[++cnt]=l%10;
        l/=10;
    }
    ans=(ans-dfs(cnt,,0)+mod)%mod;
}

例题:

诡异数字

7的意志

美丽数

概率 DP

概率 dp 的基础是求出概率或期望基于状态的转移方程。即,假定我们当前位于 $s$ 状态,接下来我们分别有 $p_1,p_2, \dots ,p_k$ 的可能性转移到 $t_1,t_2, \dots ,t_k$ 状态,那么我们就有 $f(s) = \sum p_i f(t_i)$,对于期望问题,式子也会变换为 $f(s) = \sum p_i(f(t_i)+b_i)$,其中 $b_i$ 为这一选择的消耗或收益。

然而,在列出式子之后,这些概率/期望的转移方程式可能会呈现出循环调用的情况,这时我们有两种方法解决。

  1. 当不同的式子所调用的函数个数是有限的(通常是一个)。例如这个被调用的状态是 $f(0)$,那我们可以将所有式子化成 $f(i)=A(i)f(0)+B(i)$,转而求出 $A(i),B(i)$ 即可。
  2. 高斯消元。

例题:

恶意竞争 基础题

筛子游戏 本题需要运用循环调用的解决方法

食堂 更复杂的一题

SOS DP(Sum over Subsets,子集和 DP/超集和 DP)

在子集和/超集和 dp 中,$F[sta]$ 表示所有 $sta$ 的子集/超集(含自身)的答案。

例如,二进制下 101 的子集为 101,100,001,000

二进制下 101 的超集为 101,111

然后用以下两种方法来进行状态方程的转移。

子集和

for(int i=0;i<(1<<bits);i++)//bits 为二进制下的位数
    F[i]=A[i];//赋初值
for(int i=0;i<bits;i++)
    for(int sta=(1<<bits)-1;sta>=0;sta--)
        if(sta&(1<<i))
            F[sta]+=F[sta^(1<<i)];//合并答案

超集和

for(int i=0;i<bits;i++)
    for(int sta=(1<<bits)-1;sta>=0;sta--)
        if(!(sta&(1<<i)))
            F[sta]+=F[sta^(1<<i)];

Bits And Pieces 题解

本文作者:water_tomato

评论

    发送评论 编辑评论

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