扫雷
Problem Description
扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。
晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。
Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。
保证字符串长度N <= 10000,数据组数<= 100。
Output
每行仅一个数字,表示安放地雷的方案数mod100,000,007的结果。
Sample Input
2
22
000
Sample Output
6
1
中文题意,不概述
思路: 很容易想到的是四维的 dpdpdp,利用状态压缩表示 0,1,2,30,1,2,30,1,2,3表示这一列的状态,分别表示 00,01,10,1100,01,10,1100,01,10,11。
dp[i][j][k][l]dp[i][j][k][l]dp[i][j][k][l] 表示当前在第 iii 列,第 i−1i - 1i−1 列的状态为 jjj,第 iii 列的状态为 kkk ,第 i+1i + 1i+1 列的状态为 lll
那么这样子的复杂度是 10000 * 4 * 4 * 4 * t,而时限是 1ms1ms1ms。
这里可以优化一下,复杂度 10000 * 3 * 3 * 3 * t, dp[i][j][k][l]dp[i][j][k][l]dp[i][j][k][l] 表示当前在 第 iii 列,第 i−1i - 1i−1 列雷的个数为 jjj,第 iii 列雷的个数为 kkk,第 i+1i + 1i+1 列雷的个数为 lll,那么显然有状态转移方程
if(k+l+m==str[i]−′0′) dp[i][k][l][m]=(dp[i−1][0][k][l]+dp[i−1][1][k][l]+dp[i−1][2][k][l])∗(m==1?2:1)if(k + l + m == str[i] - '0')\ \ dp[i][k][l][m] = (dp[i - 1][0][k][l] + dp[i - 1][1][k][l] + dp[i - 1][2][k][l]) * (m == 1 ? 2 : 1)if(k+l+m==str[i]−′0′) dp[i][k][l][m]=(dp[i−1][0][k][l]+dp[i−1][1][k][l]+dp[i−1][2][k][l])∗(m==1?2:1) // m==1m == 1m==1 时有两种 01 与 10
Code:
#include<bits/stdc++.h>
#define debug(x) cerr << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fi first
#define se second
#define ptch putchar
#define CLR(a) while(!(a).empty()) a.pop()
using namespace std;
inline LL read() {
LL s = 0,w = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-')
w = -1;
ch = getchar();
}
while(isdigit(ch))
s = s * 10 + ch - '0',ch = getchar();
return s * w;
}
inline void write(LL x) {
if(x < 0)
putchar('-'), x = -x;
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
#ifndef ONLINE_JUDGE
clock_t prostart = clock();
#endif
const int mod = 1e8 + 7;
const int maxn = 1e4 + 70;
int dp[maxn][3][3][3]; /// i hang, (i - 1,i,i + 1) zhuangtai
int Num[4] = {0,1,1,2};
char str[maxn];
int main() {
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
int t = read();
while(t --) {
clr(dp,0);
scanf("%s",str + 1);
int len = strlen(str + 1);
for(int j = 0; j < 4; ++ j)
for(int k = 0; k < 4; ++ k)
if(Num[j] + Num[k] == str[1] - '0')
++ dp[1][0][Num[j]][Num[k]];
for(int i = 2; i <= len; ++ i) {
for(int k = 0; k < 3; ++ k) {
if(k > str[i] - '0') break;
for(int l = 0; l < 3; ++ l) {
if(k + l > str[i] - '0') break;
for(int m = 0; m < (i == len ? 1 : 3); ++ m) {
if(k + l + m == str[i] - '0'){
dp[i][k][l][m] = (dp[i - 1][0][k][l] + dp[i - 1][1][k][l] + dp[i - 1][2][k][l]) * (m == 1 ? 2 : 1) % mod;
}
}
}
}
}
LL ans = 0;
for(int i = 0; i < 3; ++ i)
for(int j = 0; j < 3; ++ j)
ans = (ans + dp[len][i][j][0]) % mod;
write(ans);
ptch('\n');
}
#ifndef ONLINE_JUDGE
cout << "time: " << 1.0 * (clock() - prostart) / CLOCKS_PER_SEC << " s" << endl;
#endif
return 0;
}