扫雷
扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个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
思路:
这个题目的思考角度和我之前在cf上pipes思路很类似!(上次没做出来,这次也是o(╥﹏╥)o)
对于这道题目,一共有3行n列,我们可以从列的角度出发,每次一列一列的放地雷数量:
我们令num[i]为第2行i列的周围地雷数量(即题目提供的)
令dp[i]来记录每一列的地雷数,那么我们有:
dp[i]=num[i-1]-dp[i-1]-dp[i-2]
因为地雷的数量是环环相扣的,我们可以枚举第一列的数量,就可以得到之后每一列的数量——
如果一列的数量为0或2,该列只有一种放地雷的可能;如果一列的数量为1,该列有上下两种可能
代码如下:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int mx=1e4+10;
const int mod=1e8+7;//老实说这个最坑,一般都是1e9+7
int dp[mx],num[mx];
char s[mx];//dp[i]=num[i-1]-dp[i-1]-dp[i-2];
ll ans,cnt;
int main(){
int t;
scanf("%d",&t);
while(t--){
ans=0;
memset(dp,0,sizeof(dp));
scanf("%s",s+1);
int l=strlen(s+1);
for(int i=1;i<=l;i++)
num[i]=s[i]-'0';
for(int i=0;i<=2;i++)
{
if(i>num[1])//如果第一列数量少了,就跳出
break;
int j;
dp[1]=i;
for(j=2;j<=l;j++)
{
int tmp=num[j-1]-dp[j-1]-dp[j-2];
if(tmp>2||tmp<0)//要满足每一列都在0-2之间
break;
dp[j]=tmp;
}
if(j<=l)//如果不满足跳过
continue;
if(num[l]==dp[l]+dp[l-1])//最后还需要判断一下!
{
cnt=1;
for(int i=1;i<=l;i++)
{
if(dp[i]==1)
cnt=(cnt*2)%mod;
}
ans=(ans+cnt)%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}