传送门
题意:
111维扫雷问题。
给你一个长度为lenlenlen的字符串,每一个字符串分别有五种可能性:111,000,???,222,∗*∗‘,
-
如果字符为111,则代表其相邻有一个∗*∗。
-
如果字符为000,则代表相邻没有∗*∗。
-
如果字符为222,则代表相邻有两个∗*∗
-
如果字符为∗*∗,则代表此处是地雷
-
如果字符为???,则代表有该字符能够表示为其他四种字符。
现在问你给定的字符串中能够表示多少种正确的扫雷图。并对答案mod  109+7\mod10^9+7mod109+7。
题解:
刚拿到这个题就觉得这个题很dpdpdp,奈何dpdpdp还是弱项……\dots \dots……
我们分析,对于除了???的四种字符,要使得原来的串合法,则必定需要满足:
如果当前的字符为000,则其前面必定要是000或者∗1*1∗1
如果当前的字符为222,则其前面必定要是∗*∗
如果当前的字符为∗*∗,则其前面必定∗*∗或者222或者010101
如果当前的字符为111,则前面可能是000亦可能是∗*∗。
我们发现,此时,我们可以将上述的合法条件设置成444个不同的状态,即分别为:
0∗1012∗0 \quad *1 \quad 01 \quad 2 \quad *0∗1012∗
我们发现,其他的合法的状态必定可以通过增加某个字符达到上诉4个状态。
因此我们设dp[i][j]dp[i][j]dp[i][j]代表前iii个字符串中,当前处于状态jjj时的可能性。
而根据上述的合理条件,我们不难写出一下几条状态转移方程:
如果当前字符为000,有
dp[i][0]+=dp[i−1][0]∣∣dp[i][0]+=dp[i−1][1]dp[i][0]+=dp[i-1][0]\quad || \quad dp[i][0]+=dp[i-1][1]dp[i][0]+=dp[i−1][0]∣∣dp[i][0]+=dp[i−1][1]
如果当前字符为222,有
dp[i][3]+=dp[i−1][4]dp[i][3]+=dp[i-1][4]dp[i][3]+=dp[i−1][4]
如果当前字符为∗*∗,有
dp[i][4]+=dp[i−1][2]∣∣dp[i][4]+=dp[i−1][3]∣∣dp[i][4]+=dp[i−1][4]dp[i][4]+=dp[i-1][2] \quad || \quad dp[i][4]+=dp[i-1][3] \quad ||\quad dp[i][4]+=dp[i-1][4]dp[i][4]+=dp[i−1][2]∣∣dp[i][4]+=dp[i−1][3]∣∣dp[i][4]+=dp[i−1][4]
如果当前字符为111,有
dp[i][1]+=dp[i−1][4]∣∣dp[i][2]+=dp[i−1][0]∣∣dp[i][2]+=dp[i−1][1]dp[i][1]+=dp[i-1][4] \quad || \quad dp[i][2]+=dp[i-1][0] \quad || \quad dp[i][2]+=dp[i-1][1] dp[i][1]+=dp[i−1][4]∣∣dp[i][2]+=dp[i−1][0]∣∣dp[i][2]+=dp[i−1][1]
最后如果当前的字符为???显然上述可能性均有。
最后我们需要注意开头和结尾位置的特判。
当处于开头时,显然只存在∗*∗和000的状态。
而位于结尾时,显然只存在∗*∗、000和∗1*1∗1的状态。
最后只需要线性转移并统计答案即可。
#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
char str[maxn];
int dp[maxn][6];
const int mod=1e9+7;
typedef long long ll;
int main()
{
scanf("%s",str);
int len=strlen(str);
if(str[0]=='?') dp[0][0]=1,dp[0][2]=1,dp[0][4]=1;
if(str[0]=='0') dp[0][0]=1;
if(str[0]=='*') dp[0][4]=1;
if(str[0]=='1') dp[0][3]=1;
for(int i=1;i<len;i++){
if(str[i]=='0'||str[i]=='?'){
dp[i][0]=(dp[i][0]+dp[i-1][0])%mod;
dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;
}
if(str[i]=='1'||str[i]=='?'){
dp[i][1]=(dp[i][1]+dp[i-1][4])%mod;
dp[i][2]=(dp[i][2]+dp[i-1][0])%mod;
dp[i][2]=(dp[i][2]+dp[i-1][1])%mod;
}
if(str[i]=='2'||str[i]=='?'){
dp[i][3]=(dp[i][3]+dp[i-1][4])%mod;
}
if(str[i]=='*'||str[i]=='?'){
dp[i][4]=(dp[i][4]+dp[i-1][2])%mod;
dp[i][4]=(dp[i][4]+dp[i-1][3])%mod;
dp[i][4]=(dp[i][4]+dp[i-1][4])%mod;
}
}
ll res=dp[len-1][0]+dp[len-1][1];
res%=mod;
res=(res+dp[len-1][4])%mod;
cout<<res<<endl;
}