当前位置: 首页 > news >正文

[Hdp] lc552. 学生出勤记录 II(dp+递推+状态定义+状态转移+向前转移+好题)

文章目录

    • 1. 题目来源
    • 2. 题目解析

1. 题目来源

链接:552. 学生出勤记录 II

2. 题目解析

一道正常的线性dp 问题吧,状态定义和转移都不太难。分类讨论三种情况就行了。看到 y 总写了一个根据当前状态向前进行状态转移的方法,感觉还是值得记录一下的。避免某些情况下比较难写。可以对比下常规的状态转移方式和本次的状态转移方式,体会一下区别。


思路:

  • 状态定义:f[i][j][k] 定义为长度为 i 的情况下,总共有 j 个 A,且末尾有连续个 L 的有效出勤方案数构成。
  • 状态转移:f[i][j][k] 向前转移的方式,看看末尾添加这三种方式时,下一个状态可以变化到什么,然后再将状态转移过去即可。
    • 填A:当 j 没有填过时,可以进行状态转移。状态将变为 f[i+1][j+1][0]。因为此时末尾已经变为 A,而非 L。
    • 填L:当 k 没有连续填过两次时,可以进行状态转移。状态将变为 f[i+1][j][k+1]。因为此时末尾已经变为L,它不影响 A 的数量。
    • 填P:这个没有什么限制,状态直接转移即可。状态将变为 f[i+1][j][0]

这个状态转移就是从当前位置推下一个位置是哪些,而非寻常的从当前位置,看看前一个位置是哪些。比较巧妙。

包括这个代码实现也是,细节点在于 i<n 的,因为在 i=n-1 时,会递推出来 i+1=n 的这一项状态值,所以也能算出结果。

另外也贴一下普通的状态转移代码,体会一下两者不同之处。

  • 常规的转移方式,需要枚举每一个位置的前一位可以填什么,实际上大差不差。

  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
public:int checkRecord(int n) {const int MOD = 1e9+7, N = 1e5+5;int f[N][2][3];memset(f, 0, sizeof(f));f[0][0][0] = 1;for (int i = 0; i < n; i ++ ) for (int j = 0; j < 2; j ++ )for (int k = 0; k < 3; k ++ ) {if (j < 1) f[i + 1][j + 1][0] = (f[i + 1][j + 1][0] + f[i][j][k]) % MOD; // 填A, 总数中不能出现两次 Aif (k + 1 <= 2) f[i + 1][j][k + 1] = (f[i + 1][j][k + 1] + f[i][j][k]) % MOD; // 填L, 连续的不能出现三次 Lf[i + 1][j][0] = (f[i + 1][j][0] + f[i][j][k]) % MOD; // 填P,这个肯定能转移,最后一位连续L 置为0 即可}int res = 0;for (int j = 0; j < 2; j ++ )for (int k = 0; k < 3; k ++ )res = (res + f[n][j][k]) % MOD;return res;}
};

常规转移:

class Solution {
public:int checkRecord(int n) {const int MOD = 1e9+7, N = 1e5+5;int f[N][2][3];memset(f, 0, sizeof(f));f[0][0][0] = 1;for (int i = 1; i <= n; i ++ ) {// 末尾填 pfor (int j = 0; j < 2; j ++ ) {for (int k = 0; k < 3; k ++ ) {f[i][j][0] = (f[i][j][0] + f[i - 1][j][k]) % MOD;}}// 末尾填 Afor (int k = 0; k < 3; k ++ ) {f[i][1][0] = (f[i][1][0] + f[i - 1][0][k]) % MOD;}// 末尾填 Lfor (int j = 0; j < 2; j ++ ) {for (int k = 1; k < 3; k ++ ) {f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1]) % MOD;}}} int res = 0;for (int j = 0; j < 2; j ++ )for (int k = 0; k < 3; k ++ )res = (res + f[n][j][k]) % MOD;return res;}
};

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Clichouse数据导出导入(数据迁移)
  • 重头开始嵌入式第二十三天(进程2)
  • Unity | 性能优化
  • 【分享】格力手机色界G0245D 刷REC、root、 救砖、第三方rom教程和资源
  • 论文辅导 | 基于改进灰色预测模型的港口物流需求预测研究
  • opencv图像基本操作
  • [MRCTF2020]套娃1
  • 实验五之用Processing绘画
  • 洛谷p4018题解
  • GAMES104:07游戏中渲染管线、后处理和其他的一切-学习笔记
  • 【运维】从一个git库迁移到另一个库
  • 【设计模式】工厂模式和抽象工厂模式
  • 2020 位示图
  • 十五、OpenCVSharp实现相机标定
  • 关于栈(顺序栈)的知识讲解
  • Linux CTF 逆向入门
  • Making An Indicator With Pure CSS
  • MQ框架的比较
  • MySQL QA
  • October CMS - 快速入门 9 Images And Galleries
  • React系列之 Redux 架构模式
  • ViewService——一种保证客户端与服务端同步的方法
  • 面试遇到的一些题
  • 驱动程序原理
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 一些关于Rust在2019年的思考
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 自制字幕遮挡器
  • 走向全栈之MongoDB的使用
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • #HarmonyOS:基础语法
  • #stm32整理(一)flash读写
  • (C11) 泛型表达式
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (Ruby)Ubuntu12.04安装Rails环境
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (生成器)yield与(迭代器)generator
  • (一)kafka实战——kafka源码编译启动
  • (一)模式识别——基于SVM的道路分割实验(附资源)
  • .mysql secret在哪_MYSQL基本操作(上)
  • .net 7和core版 SignalR
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET构架之我见
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [24年新算法]NRBO-XGBoost回归+交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
  • [5] CUDA线程调用与存储器架构
  • [Arduino学习] ESP8266读取DHT11数字温湿度传感器数据
  • [BT]BUUCTF刷题第9天(3.27)
  • [C++] cout、wcout无法正常输出中文字符问题的深入调查(1):各种编译器测试
  • [C++]:for循环for(int num : nums)
  • [CTSC2014]企鹅QQ