題目鏈接: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;
}