CodeForces 77 D.Domino Carpet(dp)

Description

给出七张牌的水平竖直状态如下图:
这里写图片描述
这里写图片描述
两张水平牌可以组成一个 1 × 2 块,两张竖直牌可以组成一个 2 × 1 块,给出由这些牌组成的 n × m 矩阵,要求把该矩阵划分成若干 1 × 2 块和 2 × 1 块的不交并,且需满足所有 1 × 2 块的左边块所处列不相邻,问划分方案数

Input

第一行两个整数 n , m ( 1 n , m 250 ) 表示矩阵行列数,之后输入该 n × m 矩阵

Output

输出方案数,结果模 10 9 + 7

Sample Input
这里写图片描述
Sample Output

3

Solution

所有 1 × 2 块的左边块所处列不相邻的限制使得有 1 × 2 的两列与其他列完全分离,以 d p [ j ] 表示前 j 列划分的方案数,那么若第 j 列可以由若干 2 × 1 块组成则有转移 d p [ j ] + = d p [ j 1 ] ,然后考虑第 j 列和第 j 1 列这两列出现 1 × 2 块的方案数,以 f [ i ] [ 0 / 1 ] 分别表示这两列前 i 行完全划分且不出现/出现 2 × 1 块的方案数,则有以下转移

f [ 0 ] [ 0 ] = 1 , f [ 0 ] [ 1 ] = 0

若第 i 行的两个块可以组成 1 × 2 块则 f [ i ] [ 1 ] = f [ i 1 ] [ 0 ] + f [ i 1 ] [ 1 ]

若第 i 1 行和第 i 行这四个块可以组成两个 2 × 1 块则 f [ i ] [ 0 ] = f [ i 2 ] [ 0 ] , f [ i ] [ 1 ] + = f [ i 2 ] [ 1 ]

最后 f [ n ] [ 1 ] 即为这两列出现 1 × 2 块的方案数,继而有转移 d p [ j ] + = d p [ j 2 ] f [ n ] [ 1 ] d p [ m ] 即为答案

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;
}

猜你喜欢

转载自blog.csdn.net/v5zsq/article/details/81052193
77