【GalaxyOJ-902】Mine

题面

有一个 1 维的扫雷游戏,每个格子用表示有雷,用 0/1/2 表示无 雷并且相邻格子中有 0/1/2 个雷。 给定一个仅包含?、、0、1、2 的字符串 s,问有多少种方法将所 有的?改为*/0/1/2 使其合法。

分析

dp题,思路不复杂,但是状态比较多

有一点类似于状压定义的方式,dp[i][j],表示i位置是j符号

dp[][0]->0     dp[][2]->2    dp[][3]->1 左有炸弹    dp[][4]->1右有炸弹   dp[][1]自己是炸弹 

转移就是挨着推

0:i-1位置周围无炸弹,或i-1左边有炸弹

1:i-1位置周围是两个炸弹,或i-1右边有炸弹,或i-1也是炸弹

2:i-1必须自己是炸弹

3:i-1必须是炸弹

4:i-1位置周围无炸弹,或i-1左有炸弹

需要注意的是,起点的周围不能有两个炸弹,起点的左边不能有炸弹。终点的周围不能有两个炸弹,终点的右边不能有炸弹。

#include<bits/stdc++.h>
using namespace std;
#define N 1001000
#define mod 1000000007
#define ll long long
ll n,ans,dp[N][5];
char s[N];
int main()
{
    scanf("%s",s+1);n=strlen(s+1);
    if(s[1]=='0')dp[1][0]=1;
    if(s[1]=='1')dp[1][4]=1;
    if(s[1]=='*')dp[1][1]=1;
    if(s[1]=='?')dp[1][0]=1,dp[1][1]=1,dp[1][4]=1;
    for(ll i=2;i<=n;i++)
    {
        if(s[i]=='?')
        {
            dp[i][0]=(dp[i-1][3]+dp[i-1][0])%mod;
            dp[i][1]=(dp[i-1][2]+dp[i-1][4]+dp[i-1][1])%mod;
            if(i!=n)dp[i][2]=dp[i-1][1];
            dp[i][3]=dp[i-1][1];
            if(i!=n)dp[i][4]=(dp[i-1][0]+dp[i-1][3])%mod;
        }
        else
        {
            if(s[i]=='*')dp[i][1]=(dp[i-1][2]+dp[i-1][4]+dp[i-1][1])%mod;
            if(s[i]=='0')dp[i][0]=(dp[i-1][3]+dp[i-1][0])%mod;
            if(s[i]=='1')
            {
                dp[i][3]=dp[i-1][1];
                dp[i][4]=(dp[i-1][0]+dp[i-1][3])%mod;
            }
            if(s[i]=='2')dp[i][2]=dp[i-1][1];
        }
    }
    ans=(dp[n][0]+dp[n][1]+dp[n][3])%mod;
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/NSD-email0820/p/9550173.html
今日推荐