Codeforces Round #237 (Div. 2) D - Minesweeper 1D
题意:类似于扫雷游戏,但只有行,有些格子是已知的,有些未知,‘?’表示未知,其余为已知。'0'表示左右都没有雷,'1'表示左右一共有一个雷,'2'表示左右一共有两个雷,‘*’表示本身就是雷。问合法的情况一共有多少种?
解题思路:这似乎也是可以算作是某一类dp了吧,我已经做到过若干道类似的题了。只是暂时还没人给它取名字。状态是dp[i][j],表示i位置符合j状态的有多少种合法状况。其中0<=i<len,0<=j<4。i表示在哪一个位置上,j=0表示i位置不是雷,i+1也不是雷,j=1表示i位置不是雷,但i+1是雷,j=2表示i位置是雷,i+1位置不是雷,j=3表示i和i+1都是雷。这么四种情况。然后就根据位置上的信息进行转移。方程如下:
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <math.h>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#define lowbit(x) (x&(-x))
#define ll __int64
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define new_edge(a,b,c) edge[tot].t = b , edge[tot].v = c , edge[tot].next = head[a] , head[a] = tot ++
using namespace std;
const int maxn = 1111111 ;
const int mod = 1000000007 ;
ll dp[maxn][4] ;
char s[maxn] ;
int main() {
int n , i , j , k ;
scanf ( "%s" , s + 1 ) ;
n = strlen ( s + 1 ) ;
dp[0][0] = dp[0][1] = 1 ;
for ( i = 1 ; i < n ; i ++ ) {
if ( s[i] == '0' ) {
dp[i][0] = dp[i-1][0] ;
}
if ( s[i] == '1' ) {
dp[i][0] = dp[i-1][2] ;
dp[i][1] = dp[i-1][0] ;
}
if ( s[i] == '2' ) {
dp[i][1] = dp[i-1][2] ;
}
if ( s[i] == '*' ) {
dp[i][2] = ( dp[i-1][1] + dp[i-1][3] ) % mod ;
dp[i][3] = ( dp[i-1][1] + dp[i-1][3] ) % mod ;
}
if ( s[i] == '?' ) {
dp[i][0] = ( dp[i-1][0] + dp[i-1][2] ) % mod ;
dp[i][1] = ( dp[i-1][0] + dp[i-1][2] ) % mod ;
dp[i][2] = ( dp[i-1][3] + dp[i-1][1] ) % mod ;
dp[i][3] = ( dp[i-1][1] + dp[i-1][3] ) % mod ;
}
}
// for ( i = 1 ; i < n ; i ++ )
// for ( j = 0 ; j < 4 ; j ++ )
// printf ( "dp[%d][%d] = %I64d\n" , i , j , dp[i][j] ) ;
ll ans ;
if ( s[n] == '0' ) {
ans = dp[n-1][0] ;
}
else if ( s[n] == '1' ) {
ans = dp[n-1][2] ;
}
else if ( s[n] == '2' ) {
ans = 0 ;
}
else if ( s[n] == '*' ) {
ans = ( dp[n-1][1] + dp[n-1][3] ) % mod ;
}
else {
ans = ( dp[n-1][0] + dp[n-1][1] + dp[n-1][2] + dp[n-1][3] ) % mod ;
}
printf ( "%I64d\n" , ans ) ;
return 0;
}