题解:
动态规划的状态由总天数、缺勤次数和结尾连续迟到次数决定
动态规划五部曲:
1、确定dp数组及其下标含义
dp[i][j][k]:前i天有j个‘A’且结尾有连续k个‘L’的可奖励的出勤记录的数量,其中0<=i<=n,0<=j<=1,0<=k<=2;
2、确定递推式
由dp[i-1][][]和第i天的出勤记录推dp[i][][]
如果第i天的出勤记录为‘P’,则前i天与前i-1天相比,A的数量不变,结尾连续L的数量归0
dp[i][j][0] += dp[i-1][j][k](k从0到2)
如果第i天的出勤记录为A,则前i天与前i-1天相比,A的数量加1,结尾连续L的数量归零,此时要求前i-1天的出勤记录中A的数量必须为0,否则前i天的出勤记录至少有两个A,不满足奖励条件
dp[i][1][0] += dp[i-1][0][k](k从0到2)
如果第i天的出勤记录为L,则前i天与前i-1天相比,A的数量不变,结尾连续L的数量加1,此时要求前i-1天的出勤记录中结尾连续L的数量小于2,否则会出现结尾连续三个L
dp[i][j][k] += dp[i-1][j][k-1]
3、初始化
dp[0][0][0] = 1;
4、确定遍历顺序
遍历记录的长度,根据第i天的出勤记录依次计算dp
5、举例推导dp
暂不做推导
class Solution {
public:
static constexpr int MOD = 1'000'000'007;
int checkRecord(int n) {
//动态规划 三维dp数组
vector<vector<vector<int>>> dp(n+1,vector<vector<int>>(2,vector<int>(3,0)));
//初始化
dp[0][0][0] = 1;
for(int i = 1;i<=n;i++){
//第i天出勤记录为P
for(int j = 0;j<2;j++){
for(int k = 0;k<3;k++){
dp[i][j][0] = (dp[i][j][0]+dp[i-1][j][k])%MOD;
}
}
//第i天出勤记录为A
for(int k = 0;k<3;k++){
dp[i][1][0] = (dp[i][1][0]+dp[i-1][0][k])%MOD;
}
//第i天出勤记录为L
for(int j = 0;j<2;j++){
for(int k = 1;k<3;k++){
dp[i][j][k] = (dp[i][j][k]+dp[i-1][j][k-1])%MOD;
}
}
}
//求和 dp[n][][]的和
int sum = 0;
for(int j = 0;j<2;j++){
for(int k = 0;k<3;k++){
sum = (sum+dp[n][j][k])%MOD;
}
}
return sum;
}
};