链接:
「火」皇家烈焰
@[toc]

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

帕秋莉掌握了一种火属性魔法

由于钟爱扫雷游戏,帕秋莉把自己图书馆前的走廊看作一个一维的扫雷地图,她制造了很多烈焰,排在这条走廊内

现在帕秋莉告诉你一部分烈焰的分布情况,请你告诉她可能的情况有多少种

对于一个格子,里面会有以下几种字符:

0:这个格子没有烈焰,且其左右两个格子均没有烈焰

1:这个格子没有烈焰,且其左右两个格子中只有一个烈焰

2:这个格子没有烈焰,且其左右两个格子中均有烈焰

*:这个格子有烈焰

?:未告诉你本格情况

输入描述:

一个字符串

输出描述:

输出一行,一个整数表示答案,对1e9+7取模

示例1
输入

?1?

输出

2

说明
已知第二个格子左右有一个烈焰

因此可能的情况有10和01,显然其他情况都无法满足已知条件的要求
备注:
字符串的长度为n
对于30%的数据,n≤20
对于60%的的数据,n≤1,000
对于100%的数据,n≤1,000,000

题解:

乍一看以为是扫雷。仔细一看为什么又是dp(每日一题好爱出dp,而我dp又是渣渣)

在其他大佬那吸取知识之后,写出自己的理解:

我们仔细看题可以看出,每个点什么情况其实都与两侧的点息息相关,我可以通过一个点算出两侧点的状态,也可以根据两侧状态来反推中间的点。
但是我们状态转移的顺序是从左到右,我们在转移过程中,考虑第i点时,i-1之前的点状态都是固定的,所以我们只需要考虑当前点i与之后一个点i+1的状态。
在第i点时,i+1可能也有了要求,所以不满足情况的就不用转移状态。
dp[i][0/1/2/3]:

0表示i与i+1都不是火
1表示i是火,i+1不是火
2表示i不是火,i+1是
3表示i和i+1都是火

对照题目给出的状态,

 0:这个格子没有烈焰,且其左右两个格子均没有烈焰

 1:这个格子没有烈焰,且其左右两个格子中只有一个烈焰

  2:这个格子没有烈焰,且其左右两个格子中均有烈焰

 *:这个格子有烈焰

 ?:未告诉你本格情况

具体情况如下:

if(i = = 0)
说明i-1,i,i+1都没有火,i 的状态就是等同于i-1的状态都是0(即本身与右边都不是火)
转移方程:f [i ] [ 0 ] = f [ i - 1 ] [ 0 ]

if(i = = 1)
i不是火,但是i的周围有一个火
如果左边是火,那么右边就不是火,那i就满足状态0,i-1就满足状态1:f[i][0]=f[i-1][1]
如果右边是火,左边就不是火,那么i就满足状态2,i-1就满足状态0:f [ i ][ 2 ] = f [ i - 1 ] [ 0]

if(i = = 2)
左右均为火,那么i-1是火,i不是火,i+1是火,i就满足状态2: f [ i ] [ 2 ] =f [ i-1 ] [ 1 ]

if(i = = *)
当前i为火,I+1有两种情况,
一个是i+1位火:
f [ i ] [ 3 ]= f [ i - 1 ] [ 2 ] + f [ i - 1 ] [ 3 ]
i+1不是火:
f [ i ] [ 1 ] = f [ i - 1 ] [ 2 ] + f [ i - 1 ] [ 3 ]

if(i = = ?)
当前点未知,我们就要考虑所有情况
i为火,i不为火,i+1为火,i+1不为火
四种情况:
i与i+1都不是火:
f [ i ] [0 ] = f[ i - 1 ][ 0 ] + f [i - 1 ] [ 1 ]

i不是,i+1是火
f [ i ] [ 2 ] = f [ i - 1 ] [ 0 ] + f [ i - 1 ] [ 1 ]

i是火,i+1不是
f [ i ] [ 1 ] = f [ i - 1 ] [ 2 ] + f [i - 1 ] [ 3 ]

i和i+1都是火
f [ i ] [ 3 ] = f [ i - 1 ] [ 2 ] + f [ i - 1 ][ 3 ]

到最后一个点i,i后面没有点了,相当于i+1不是火
答案就是
i是火与不是火了两种情况加一起
f [ i ] [ 0 ] + f [ i ] [ 1 ]
此时i=地图长度

对了前往不要忘了取模mod

结合我讲的,在代码里面一条一条对应

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1,mod=1e9+7;
int f[maxn][7];
char s[maxn];
int main()
{
    f[0][0]=f[0][2]=1; 
    cin>>s;
    int len=strlen(s);

    for(int i=1;i<=len;++i)
    {
        if(s[i-1]=='0')
        {
            f[i][0]=f[i-1][0];
        }
        else if(s[i-1]=='1')
        {
            f[i][0]=f[i-1][1];

            f[i][2]=f[i-1][0];
        }
        else if(s[i-1]=='2')
        {
            f[i][2]=f[i-1][1];
        }
        else if(s[i-1]=='*'){

            f[i][1]=(f[i-1][2]+f[i-1][3])%mod;

            f[i][3]=(f[i-1][2]+f[i-1][3])%mod;

        }
        else if(s[i-1]=='?'){

            f[i][0]=(f[i-1][0]+f[i-1][1])%mod;

            f[i][2]=(f[i-1][0]+f[i-1][1])%mod;

            f[i][1]=(f[i-1][2]+f[i-1][3])%mod;

            f[i][3]=(f[i-1][2]+f[i-1][3])%mod;

        }
    }
    cout<<(f[len][0]+f[len][1])%mod;
    return 0;
}