CF404D Minesweeper 1D(dp)

題目鏈接:D. Minesweeper 1D 【一維掃雷】

題意:

一維掃雷,每個位置可能爲'0', '1', '2', '*'。‘*’表示雷,0 1 2 都表示其左右的雷的數量,現在給出一個一維掃雷的地圖(|s|<=1e6),其中有一些字符'?',這些‘?’可以是以上四個值的任意一種,問有多少種合法的地圖。

輸入樣例:

?01???

輸出樣例:

4

輸入樣例:

?

輸出樣例:

2

題目分析:

對於每個位置,要麼是雷,要麼不是雷,但是數字會限制其左右的雷的數量。

如果前一個位置爲數字,假設左邊情況已經是已知的,那麼這一位是否爲雷也是確切的。

如果前一個位置爲雷,那麼這個位置可以爲雷,也可以爲數字。

定義一下三種狀態,

0:這一位不是雷。下一位不是雷。

1:這一位不是雷。下一位是雷。

2:這一位是雷。下一位可以是雷,也可以不是雷。

dp初始條件是dp[0][0] = dp[1][0] = 1;

初始位置下標1前面是沒有雷的,但是下標1可以是雷也可以不是雷

那麼轉移dp[i]的方式就取決於s[i]是什麼了,分類討論即可

代碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1000005;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
int n, p;
typedef pair<int,int> P;
char s[MAXN];
int dp[MAXN][3];
//0:x/x  1:x/*  2:*/?
inline void ADD(int &a, int &b){
    a += b; if(a >= mod) a-= mod;
}
int main(){
    scanf("%s",s+1);
    n = strlen(s+1);
    dp[0][0] = dp[0][1] = 1;
    for(int i = 1;i<=n;i++){
        if(s[i] == '0' || s[i] == '?'){
            ADD(dp[i][0], dp[i-1][0]);
        }
        if(s[i] == '1' || s[i] == '?'){
            ADD(dp[i][1], dp[i-1][0]);
            ADD(dp[i][0], dp[i-1][2]);
        }
        if(s[i] == '2' || s[i] == '?'){
            ADD(dp[i][1], dp[i-1][2]);
        }
        if(s[i] == '*' || s[i] == '?'){
            ADD(dp[i][2], dp[i-1][1]);
            ADD(dp[i][2], dp[i-1][2]);
        }
    }
    ADD(dp[n][0],dp[n][2]);
    printf("%d\n",dp[n][0]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章