题目链接:
http://codeforces.com/problemset/problem/404/D
Game "Minesweeper 1D" is played on a line of squares, the line's height is 1 square, the line's width is n squares. Some of the squares contain bombs. If a square doesn't contain a bomb, then it contains a number from 0 to 2 — the total number of bombs in adjacent squares.
For example, the correct field to play looks like that: 001*2***101*. The cells that are marked with "*" contain bombs. Note that on the correct field the numbers represent the number of bombs in adjacent cells. For example, field 2* is not correct, because cell with value 2 must have two adjacent cells with bombs.
Valera wants to make a correct field to play "Minesweeper 1D". He has already painted a squared field with width of n cells, put several bombs on the field and wrote numbers into some cells. Now he wonders how many ways to fill the remaining cells with bombs and numbers are there if we should get a correct field in the end.
The first line contains sequence of characters without spaces s1s2... sn (1 ≤ n ≤ 106), containing only characters "*", "?" and digits "0", "1" or "2". If character si equals "*", then the i-th cell of the field contains a bomb. If character si equals "?", then Valera hasn't yet decided what to put in the i-th cell. Character si, that is equal to a digit, represents the digit written in the i-th square.
Print a single integer — the number of ways Valera can fill the empty cells and get a correct field.
As the answer can be rather large, print it modulo 1000000007 (109 + 7).
?01???
4
?
2
**12
0
1
0
In the first test sample you can get the following correct fields: 001**1, 001***, 001*2*, 001*10.
题目意思:
模拟扫雷,不过是在一行上。如果为*表示地雷,?表示当前不确定,0、1、2表示左右存在的地雷的个数。求在该限制下,共有多少种排法。
实际上是给定一些限制,满足要求的种数。
解题思路:
计数dp.
这题的dp的状态的意义有点特殊,用一个数字表示当前与后面一个的关系其实可以压成二维的。
dp[i][0]:表示当前位置i的不是地雷,并且i+1也不是雷
dp[i][1]:表示当前位置i的不是地雷,并且i+1是地雷
dp[i][2]:表示当前位置i的是地雷,并且i+1不是地雷
dp[i][3]:表示当前位置i的是地雷,并且i+1也是地雷
转移见图:
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100000 char save[Maxn]; ll dp[Maxn][4]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(~scanf("%s",save+1)) { int n=strlen(save+1); memset(dp,0,sizeof(dp)); dp[0][0]=dp[0][1]=1; for(int i=1;i<n;i++) { if(save[i]=='0') //当前不是雷,后面也不是雷,前面也不是雷 dp[i][0]=dp[i-1][0]; else if(save[i]=='1') //当前不是雷,前面或后面有一个雷 { dp[i][0]=dp[i-1][2]; //如果前面是雷,后面不是雷 dp[i][1]=dp[i-1][0]; //如果后面是雷,前面不是雷 } else if(save[i]=='2') //当前不是雷,前面后面都是雷 dp[i][1]=dp[i-1][2]; else if(save[i]=='*') //当前是雷 { dp[i][2]=(dp[i-1][1]+dp[i-1][3])%M; dp[i][3]=(dp[i-1][1]+dp[i-1][3])%M; } else if(save[i]=='?') { dp[i][0]=(dp[i-1][0]+dp[i-1][2])%M; dp[i][1]=(dp[i-1][0]+dp[i-1][2])%M; dp[i][2]=(dp[i-1][1]+dp[i-1][3])%M; dp[i][3]=(dp[i-1][1]+dp[i-1][3])%M; } } ll ans=0; if(save[n]=='0') //当前不是雷,前面一个也不是雷 ans=dp[n-1][0]; else if(save[n]=='1')//当前不是雷,前面一个是雷 ans=dp[n-1][2]; else if(save[n]=='2') //不可能 ans=0; else if(save[n]=='*')a ans=(dp[n-1][1]+dp[n-1][3])%M; else { ans=(dp[n-1][0]+dp[n-1][1]+dp[n-1][2]+dp[n-1][3])%M; } printf("%I64d\n",ans); } return 0; }