多状态DP

前置知识

dp的四步法(水字数)

  1. 确定状态
  2. 确定答案
  3. 确定状态转移方程
  4. 确定初始状态和边界

P1644 跳马问题

pA7BeWF.png

一共就上面的四个方向,并且并没有单调性,所以for循环时先设行,再设列。

知识点:

​ 如果dp中并没有单调性,进行状态转移方程的for循环要先跑列,再跑行。

  1. 确定状态:dp[i][j] 直接代表 \(0,0\) 可以直接到达 \(i,j\) 的方案数。

  2. 确定答案:dp[n][m]

  3. 确定状态转移方程:dp[i][j] = dp[i+2][j-1] + dp[i+1][j-2] + dp[i - 1][j -2] + dp[i -2][j- 1]

  4. 确定初始状态和边界:

    dp[0][0]=1 //0,0开始的方案数是1
    dp[i][j]=0;//不存在方案是0
    

D1320 【例3.4】昆虫繁殖

这道题的思路就比上一道题的模拟dfs的过程完全不相同,因为这里要搞两个值,并且是相互依赖的。

两种形态:幼虫和成虫。

依赖关系:幼虫可以直接转变为成虫,成虫可以继续繁殖有幼虫。

随着月份的增加,整个过程一直在递增,后面的状态不会影响前面的状态

温馨提示:

dp真正有效果的时候,是问题中包含重叠子问题

​ 比如最熟悉的斐波那契数列,直接递归(如dfs)存在很多重复情况,dp本质是空间换时间,记忆化

  1. 确定状态:baby[i] 表示在第 \(i\) 个月幼虫的数量,dp[i] 表示在第 \(i\) 个月成虫的数量。

  2. 确定答案:dp[z]

  3. 确定状态转移方程。

    baby[i] = dp[i - x] * y;   // 得到新生的幼虫数量 每队幼虫只使用一次,保证答案唯一
    dp[i] = dp[i - 1] + baby[i - 2]; // 得到成虫的数量
    
  4. 确定初始值和边界:

    dp[1-x] = 1;
    baby[0] = 0; // 初始条件
    

P7158 「dWoi R1」Password of Shady

这道题有两种写法:

大暴力(30pts)

直接求出范围,然后for循环一个一个枚举和判断,直接求出答案。

dp(100pts)

实际上这道题给出的 \(k\) 没有用,因为 \(k\) 的值不会为0,所以所有值最后求出来的结果都是一样的。

这道题的题目隐藏了偶数的“反义词”——奇数,在求值中奇数和偶数是互补的

  1. 确定状态

    dp[0][i] //表示有i位数字有偶数个k的总情况数量
    dp[1][i] //表示有i位数字有奇数个k的总情况数量
    或者
    dp1[i] //表示有i位数字有偶数个k的总情况数量
    dp2[i] //表示有i位数字有奇数个k的总情况数量
    
  2. 确定答案:dp1[i]dp[0][i],输出偶数的答案

  3. 确定状态转移方程

    dp[0][i] = dp[0][i - 1] * 9 + dp[1][i - 1]
    dp[1][i] = dp[1][i - 1] * 9 + dp[0][i - 1]
    
  4. 确定初始值和边界情况

    dp[0][1] = 1;
    dp[1][1] = 8;// 因为不存在前导0
    

P8395 [CCC2022 S1] Good Fours and Good Fives

这个就是数字拆分的模板,只有两个数字,4和5。

这道题还有一个加强版,P1806 跑步,这个题就是数字设定范围,问整个范围内的方案数。

本题不能直接dp[i] = dp[i - 4] + dp[i - 5],会有重复,如下图:

pA7BokV.png

  1. 确定状态

    按照从小到大的顺序构建

    dp1[i]//表示以4结尾的方案数
    dp2[i]//表示以5结尾的方案数
    
  2. 确定答案:dp1[n]+dp2[n]

  3. 确定状态转移方程

    dp1[i] = dp1[i - 4];
    dp2[i] = dpl[i - 4] + dp2[i - 5];
    
  4. 确定初始值和边界情况

    dp1[4]= 1;
    dp2[5] = 1;
    

结(24/12/8/0:14)

posted @ 2024-12-08 00:15  非气盈门  阅读(70)  评论(0)    收藏  举报