题目大意

略。

题解

由于每一个位置上的描述会涉及当前状态及相邻状态,用 表示**满足前 个字符的要求**,且当前位置状态为 ,后一个位置状态为 时的方案数目。则转移方程不难写出。

初始状态为 ,答案为

理论上只刻画当前状态和此前状态似乎也可以,但是讨论就很麻烦。

#include <bits/stdc++.h>
#define INF 2000000000
#define M 1000000007
using namespace std;
typedef long long ll;
int read(){
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
    while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
    return f * x; 
}
int n, f[1000005][2][2] = {0};
char s[1000005];
void init(){
    scanf("%s", s);
    n = strlen(s);
}
void solve(){
    f[0][0][0] = f[0][0][1] = 1;
    for (int i = 1; i <= n; ++i){
        if (s[i - 1] == '0'){
            f[i][0][0] = f[i - 1][0][0];
        }else if (s[i - 1] == '1'){
            f[i][0][0] = f[i - 1][1][0];
            f[i][0][1] = f[i - 1][0][0];
        }else if (s[i - 1] == '2'){
            f[i][0][1] = f[i - 1][1][0];
        }else if (s[i - 1] == '*'){
            f[i][1][0] = f[i][1][1] = (f[i - 1][0][1] + f[i - 1][1][1]) % M;
        }else {
            f[i][0][0] = f[i][0][1] = (f[i - 1][0][0] + f[i - 1][1][0]) % M;
            f[i][1][0] = f[i][1][1] = (f[i - 1][0][1] + f[i - 1][1][1]) % M;
        }
    }
    int ans = (f[n][1][0] + f[n][0][0]);
    printf("%d\n", ans);
}
int main(){
    init();
    solve();
    return 0;
}

小结

本题的状态刻画比较精妙。看来寻找一个好的状态表示还是要从题目出发,单靠经验有的时候会使问题复杂化。