题干:
扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个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
解题报告:
直接dp[n][3][3],dp[i][j][k]代表第i列放置了j个地雷,第i-1列放置k个地雷的前缀合法方案数。更新的时候直接更新到第n+1列,这样就不用特判了。直接取值就行。注意注释掉的那一句,不需要特判,当时是想的,剩下那些状态都是非法的了,所以不需要进行更新了,但是其实更新了也没关系,因为反正也用不到,也就是说你可以更新了,但是不取这个值就可以了。
再就是数组需要开到dp[n][9][9],因为虽然你用不到这些值,但是你状态转移方程中可能会用到这些非法值,所以为了防止越界,需要数组开大一点。(当然,你直接用ifelse特判掉越界情况也可以,但是比较麻烦)
至于为什么要更新到n+1列,是因为你更新到第i列的时候,可完全确定的是第i-1列的值,所以要完全确定第n列的值,需要第n+1列的状态,只不过取 让第n+1列放置地雷个数为0 的状态就好了。
其实还有更简单的方法,因为第一列的值定下来,通过s[1],第二列地雷肯定也是定的,而通过s[2]又可以确定s[3],以此类推,所以只要第一列的值确定了,后面的值都确定了,所以也可以直接递推过去。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 20000 + 5;
const ll mod = 100000007;
char s[MAX];
ll dp[MAX][10][10];
int main()
{int T;cin>>T;while(T--) {scanf("%s",s+1);int n = strlen(s+1);s[n+1]=s[n]+9;for(int i = 1; i<=n+1; i++) {for(int j = 0; j<3; j++) {for(int k = 0; k<3; k++) dp[i][j][k]=0;}}for(int j = 0; j<3; j++) {if(j > s[1]-'0') continue;if(j == 1) dp[1][j][0]=2;else dp[1][j][0]=1;}for(int i = 2; i<=n+1; i++) {for(int j = 0; j<3; j++) {
// if(i == n+1 && j>0) continue;for(int k = 0; k<3; k++) {if(s[i]-'0' < j+k) continue;if(s[i-1]-'0' < j+k) continue;//这句去掉其实也能过,但是有RE风险dp[i][j][k] += dp[i-1][k][s[i-1]-'0'-j-k];if(j == 1) dp[i][j][k] += dp[i-1][k][s[i-1]-'0'-j-k];dp[i][j][k] %= mod;}}}ll ans = 0;for(int k = 0; k<3; k++) ans = (ans+dp[n+1][0][k])%mod;printf("%lld\n",ans);}return 0 ;
}