Description
给出七张牌的水平竖直状态如下图:
两张水平牌可以组成一个
块,两张竖直牌可以组成一个
块,给出由这些牌组成的
矩阵,要求把该矩阵划分成若干
块和
块的不交并,且需满足所有
块的左边块所处列不相邻,问划分方案数
Input
第一行两个整数 表示矩阵行列数,之后输入该 矩阵
Output
输出方案数,结果模
Sample Input
Sample Output
3
Solution
所有 块的左边块所处列不相邻的限制使得有 的两列与其他列完全分离,以 表示前 列划分的方案数,那么若第 列可以由若干 块组成则有转移 ,然后考虑第 列和第 列这两列出现 块的方案数,以 分别表示这两列前 行完全划分且不出现/出现 块的方案数,则有以下转移
若第 行的两个块可以组成 块则
若第 行和第 行这四个块可以组成两个 块则
最后 即为这两列出现 块的方案数,继而有转移 , 即为答案
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=255;
#define mod 1000000007
int n,m,type[maxn][maxn],dp[maxn],f[maxn][2];
char s[3][maxn*5];
//0 hor
//1 ver
//2 both
int Solve(int L,int R)
{
int num=0;
for(int i=0;i<3;i++)
for(int j=L;j<=R;j++)
if(s[i][j]=='O')num++;
if(num==2||num==3)
{
if(s[0][R]=='O')return 1;
return 0;
}
if(num==6)
{
if(s[1][L]=='O')return 1;
return 0;
}
return 2;
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s[0]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<3;j++)scanf("%s",s[j]);
int L=1,R=3;
for(int j=1;j<=m;j++)
{
type[i][j]=Solve(L,R);
L+=4,R+=4;
}
scanf("%s",s[0]);
}
//for(int i=1;i<=n;i++)
// for(int j=1;j<=m;j++)
// printf("%d%c",type[i][j],j==m?'\n':' ');
dp[0]=1;
for(int j=1;j<=m;j++)
{
if(n%2==0)
{
int flag=1;
for(int i=1;i<=n;i++)
if(type[i][j]==0)
{
flag=0;
break;
}
if(flag)dp[j]=(dp[j]+dp[j-1])%mod;
}
if(j>1)
{
f[0][0]=1,f[0][1]=0;
for(int i=1;i<=n;i++)
{
f[i][0]=f[i][1]=0;
if(type[i][j-1]!=1&&type[i][j]!=1)f[i][1]=(f[i-1][0]+f[i-1][1])%mod;
if(i==1)continue;
if(type[i-1][j-1]&&type[i-1][j]&&type[i][j-1]&&type[i][j])
{
f[i][1]=(f[i][1]+f[i-2][1])%mod;
f[i][0]=(f[i][0]+f[i-2][0])%mod;
}
}
dp[j]=(dp[j]+(ll)dp[j-2]*f[n][1]%mod)%mod;
}
}
printf("%d\n",dp[m]);
return 0;
}