Fourth day

· · 个人记录

\huge\color{blue}\text{DP}$ $\tiny\color{pink} dynamic programming $ $\huge\color{blue}\text{动态规划}

数位DP

可以先做一个前缀和,则 [l,r] 可以看成 [0,r] - [0,l-1]
所以可以转化为

[0,x] 里面数的个数
x 按位写下来 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \overline{x_kx_{k-1}x_{k-2} \cdots x_{1}}
找一个 0≤y≤x 按位写成 \overline{y_ky_{k-1}y_{k-2} \cdots y_1}

也就是找到 y_ky_{k-1}y_{k-2} \cdots y_1 总共有多少种可能使得 y≤x

DP方式就是\color{orange}\text{从高位向低位一位一位地赋值}

f[i][j] $j$ 表示填完当前的位后 $\begin{cases}\text{0代表} <x \\ \text{1代表} =x\\\end{cases}

\color{pink}\text{数位DP的套路}

  1. 前缀和转化:
    由求 [l,r] 转化为求 [0,r] - [0,l]
  2. 状态设计: f[i][j] $j$ 表示填完当前的位后 $\begin{cases}\text{0代表} <x \text{ 决定下一位可以填 0-9}\\ \text{1代表} =x \text{ 决定下一位可以填 0-}x_{i-1}\\\end{cases}
  3. 初始化: x$ 有 $k$ 位,$f[k+1][1] = 1
  4. 状态转移:
    枚举 i - 1 位填什么即可

例题

\color{lightblue}\large T1 \color{lightblue}\large T2

在上一问的基础上增加一维, k 表示第 i 位填的数是什么
即, f[i][j][k]

同时,除此之外还需要 \color{orange}\text{考虑前导零} ,例如:0001357是合法的

\color{lightblue}\large T3

[L,R] 之间的一个 max ,因此不能用前缀和相减,即 LR 拆不开

由此,状态应该修改

f[i][j][k] $j$ 表示填完当前的位后 $\begin {cases}j=\text{0代表} x<R \\ j=\text{1代表} x=R \\\end{cases} k$ 表示填完当前的位后 $\begin{cases}k=\text{0代表} x>L \\ k=\text{1代表} x=L \\\end{cases}

增加一维度 k 来限制 x 的左边界即可

另外还需要一个维度 p 代表当前位填的数是什么

所以状态: f[i][j][k][p]

依次枚举上一位的 p 来转移当前位即可

排列DP

定义状态:

$i$ 表示已经把 $1$ 到 $i$ 插入进去 $j$ 表示逆序对数量为 $j

初始化: f[1][0] = 11 - 1 的排列形成0个逆序对的方案数为 1

枚举方法: 把第 i 个数插入到的位置

优化方法:第二维度 j 只考虑奇偶即可,即 j 只能为 01

例题

\color{lightblue}\large T1

正着插入第 i 个数会影响到后面数
而倒着插入并不会影响到后面的数,所以选择倒着插入 i

\large\color{pink}\text{排列DP可以选择正着插入或者倒着插入,视情况而定}

所以定义状态: f[i][j]i 表示倒着从 n 排到了 ij 表示当前激动值

由于插入的 i 是已经插入的数里面的最小的一个,所以只有当 i 插入到最前面的时候 f[i][j] 才会 +1

\color{lightblue}\large T2 $j$ 是对所有的长度为 $2$ 的最长上升子序列找出来,对他们的第二个下标求 min 转移:枚举 $[0,j-1]$ ,将 $i$ 插入在 $[0,j-1]$ 处