感想
处理这种某一个位置会影响其相邻位置的题型原来可以这样设DP状态式
我菜到真实


解题思路参考
https://blog.nowcoder.net/n/c172ed50c89843218584524ea4197bcc?&toCommentId=6079660


思路
图片说明
图片说明
其实,我觉得如果你的状态表示成这样,那么状态转移时应该SO EASY,所以,我就直接贴转移代码了


其实,是不是看到这内心有一点疑惑,为什么我们不需要考虑第i + 1位上的数字是0还是1还是2还是*还是?呢
这其实也就是动态规划的思想,当我们考虑前i位时,我们并不需要关心第i+1位的情况。
如果dp[i][i的状态一定正确,但i + 1的状态不确定],那么我们在枚举到i+1时,i+1的状态一定正确,我们只需要在更新时,找到dp[i][i的状态正确,i+1状态也正确(因为我们现在正在枚举第i + 1状态)]的结果就可以了,这样一路更新过去,就保证答案的正确性。
YY半天,不知道大家懂不懂
这也就是为什么初始化dp[0][0] = dp[0][1] = 1;
因为第0位的状态一定是无火,但是第1位我们不需要考虑
这也就是为什么答案是dp[n][0] + dp[n][2];
因为第n + 1位的状态一定是无火,所以用n+1明确的状态在dp[n][第n位状态一定正确, 第n+1位状态]里面找转移式子


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 1e9 + 7;
ll dp[maxn][5];
char s[maxn];
int n;
int main(){
    scanf("%s", s + 1);
    n = strlen(s + 1);
    dp[0][0] = dp[0][1] = 1;
    for(int i = 1; i <= n; i++){
        if(s[i] == '0'){
            dp[i][0] = dp[i - 1][0];
        }
        else if(s[i] == '1'){
            dp[i][1] = dp[i - 1][0];
            dp[i][0] = dp[i - 1][2];
        }
        else if(s[i] == '2'){
            dp[i][1] = dp[i - 1][2];
        }
        else if(s[i] == '*'){
            dp[i][2] = dp[i][3] = (dp[i - 1][1] + dp[i - 1][3]) % mod;
        }
        else{
            dp[i][0] = dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % mod;
            dp[i][2] = dp[i][3] = (dp[i - 1][1] + dp[i - 1][3]) % mod;
        }
    }
    printf("%lld\n", (dp[n][0] + dp[n][2]) % mod);
    return 0;
}