其他分享
首页 > 其他分享> > cf404 D. Minesweeper 1D(dp后效性,分类讨论)

cf404 D. Minesweeper 1D(dp后效性,分类讨论)

作者:互联网

题意:

一维扫雷游戏,*表示有雷,0/1/2表示周围有几个雷。棋盘上的一些位置已知,一些位置未知(用?表示),求合法的棋盘数。

思路:

有一点点后效性,讨论就完事了。

\(f[i][state]\),\(state\) 为第 \(i\) 个位置的状态:0左右没雷,1左边有雷右边没雷,2左边没雷右边有雷,3左右有雷,4这里有雷但对左右无要求。(状态0~3都是这里没雷)

\(s[i]=*\implies f[i][4]=f[i-1][2]+f[i-1][3]+f[i-1][4]\)

\(s[i]=0\implies f[i][0]=f[i-1][0]+f[i-1][1]\)

\(s[i]=2\implies f[i][3]=f[i-1][4]\)

\(s[i]=1\implies f[i][1]=f[i-1][4],f[i][2]=f[i-1][0]+f[i-1][1]\)

初值:不妨假设 \(-1\) 位置没雷,\(0\) 位置没雷, \(1\) 位置可能有雷也可能没雷。则 \(f[0][0]=f[0][2]=1\)

(当然也可以设 \(-1\) 有雷,\(0\) 还是没雷,则 \(f[0][1]=f[0][3]=1\))

答案:第 \(n+1\) 位没雷,所以答案是 \(f[n][0]+f[n][1]+f[n][4]\)

const int N = 1e6 + 5, MOD = 1e9 + 7;
ll n, f[N][6];
char s[N];

signed main()
{
    cin >> (s + 1); n = strlen(s + 1);

    f[0][0] = f[0][2] = 1;

    for(int i = 1; i <= n; i++)
    {
        if(s[i] == '*' || s[i] == '?')
            f[i][4] = (f[i-1][2] + f[i-1][3] + f[i-1][4]) % MOD;
        if(s[i] == '0' || s[i] == '?')
            f[i][0] = (f[i-1][0] + f[i-1][1]) % MOD;
        if(s[i] == '2' || s[i] == '?')
            f[i][3] = f[i-1][4];
        if(s[i] == '1' || s[i] == '?')
            f[i][1] = f[i-1][4], f[i][2] = (f[i-1][0] + f[i-1][1]) % MOD;
    }

    cout << (f[n][0] + f[n][1] + f[n][4]) % MOD;
}

标签:后效,cf404,implies,int,Minesweeper,位置,有雷,没雷
来源: https://www.cnblogs.com/wushansinger/p/15863996.html