Description
求n*m区域用2*1和1*2的骨牌铺满且没有横竖割线的方案数
Input
多组用例,每组用例占一行包括两个整数n和m,以文件尾结束输入(1<=m,n<=16)
Output
对于每组用例,输出合法方案数,结果模1e9+7
Sample Input
2 2
5 6
8 7
Sample Output
0
6
13514
Solution
首先用轮廓线DP求出不加限制的方案数,t[n][m]表示n*m区域用骨牌铺满的方案数,这个复杂度过高所以可以打表,然后对列容斥,2^(m-1)枚举列割线状态,然后计算列割线状态包括sta且没有行割线的方案数f[n](其中列割线状态包括sta的意思是列分隔线含有sta状态的所有列割线,但也可能含有其他列割线),求法就是用总方案数减去有横割线的方案,令f[i]表示前i行列割线状态包括sta且没有行割线的方案数,设sta状态有num条列割线,这num条列割线将m列分成了num+1块,每块长度为l[0],…,l[num],那么总方案数为,然后枚举第一条横割线位置来求不合法方案数,假设第一条横割线在第j行与第j+1行间,那么这种情况下的方案数即为
,故
那么对于每个状态sta都可以在O(n^2)内求出f[n],然后根据这个状态列割线num的数目进行容斥即可,奇减偶加(代码中奇加偶减是因为代码中num值是真实列割线数加一),总时间复杂度
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;
#define INF 0x3f3f3f3f
#define mod 1000000007ll
#define maxn 20
ll dp[2][1<<maxn],t[maxn][maxn],l[maxn],f[maxn];
void init()
{
for(int n=1;n<=16;n++)
for(int m=1;m<=16;m++)
{
int cur=0,M=(1<<m)-1;
memset(dp,0,sizeof(dp));
dp[0][M]=1;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cur^=1;
memset(dp[cur],0,sizeof(dp[cur]));
for(int sta=0;sta<1<<m;sta++)
if(dp[cur^1][sta])
{
if(!(sta&(1<<m-1)))
{
dp[cur][((sta<<1)|1)&M]+=dp[cur^1][sta];
dp[cur][((sta<<1)|1)&M]%=mod;
}
else
{
dp[cur][(sta<<1)&M]+=dp[cur^1][sta];
dp[cur][(sta<<1)&M]%=mod;
if(j&&!(sta&1))
{
dp[cur][((sta<<1)|3)&M]+=dp[cur^1][sta];
dp[cur][((sta<<1)|3)&M]%=mod;
}
}
}
}
printf("t[%d][%d]=%I64d;\n",n,m,dp[cur][M]);
}
}
void get_table()
{
t[1][1]=0;
t[1][2]=1;
t[1][3]=0;
t[1][4]=1;
t[1][5]=0;
t[1][6]=1;
t[1][7]=0;
t[1][8]=1;
t[1][9]=0;
t[1][10]=1;
t[1][11]=0;
t[1][12]=1;
t[1][13]=0;
t[1][14]=1;
t[1][15]=0;
t[1][16]=1;
t[2][1]=1;
t[2][2]=2;
t[2][3]=3;
t[2][4]=5;
t[2][5]=8;
t[2][6]=13;
t[2][7]=21;
t[2][8]=34;
t[2][9]=55;
t[2][10]=89;
t[2][11]=144;
t[2][12]=233;
t[2][13]=377;
t[2][14]=610;
t[2][15]=987;
t[2][16]=1597;
t[3][1]=0;
t[3][2]=3;
t[3][3]=0;
t[3][4]=11;
t[3][5]=0;
t[3][6]=41;
t[3][7]=0;
t[3][8]=153;
t[3][9]=0;
t[3][10]=571;
t[3][11]=0;
t[3][12]=2131;
t[3][13]=0;
t[3][14]=7953;
t[3][15]=0;
t[3][16]=29681;
t[4][1]=1;
t[4][2]=5;
t[4][3]=11;
t[4][4]=36;
t[4][5]=95;
t[4][6]=281;
t[4][7]=781;
t[4][8]=2245;
t[4][9]=6336;
t[4][10]=18061;
t[4][11]=51205;
t[4][12]=145601;
t[4][13]=413351;
t[4][14]=1174500;
t[4][15]=3335651;
t[4][16]=9475901;
t[5][1]=0;
t[5][2]=8;
t[5][3]=0;
t[5][4]=95;
t[5][5]=0;
t[5][6]=1183;
t[5][7]=0;
t[5][8]=14824;
t[5][9]=0;
t[5][10]=185921;
t[5][11]=0;
t[5][12]=2332097;
t[5][13]=0;
t[5][14]=29253160;
t[5][15]=0;
t[5][16]=366944287;
t[6][1]=1;
t[6][2]=13;
t[6][3]=41;
t[6][4]=281;
t[6][5]=1183;
t[6][6]=6728;
t[6][7]=31529;
t[6][8]=167089;
t[6][9]=817991;
t[6][10]=4213133;
t[6][11]=21001799;
t[6][12]=106912793;
t[6][13]=536948224;
t[6][14]=720246619;
t[6][15]=704300462;
t[6][16]=289288426;
t[7][1]=0;
t[7][2]=21;
t[7][3]=0;
t[7][4]=781;
t[7][5]=0;
t[7][6]=31529;
t[7][7]=0;
t[7][8]=1292697;
t[7][9]=0;
t[7][10]=53175517;
t[7][11]=0;
t[7][12]=188978103;
t[7][13]=0;
t[7][14]=124166811;
t[7][15]=0;
t[7][16]=708175999;
t[8][1]=1;
t[8][2]=34;
t[8][3]=153;
t[8][4]=2245;
t[8][5]=14824;
t[8][6]=167089;
t[8][7]=1292697;
t[8][8]=12988816;
t[8][9]=108435745;
t[8][10]=31151234;
t[8][11]=940739768;
t[8][12]=741005255;
t[8][13]=164248716;
t[8][14]=498190405;
t[8][15]=200052235;
t[8][16]=282756494;
t[9][1]=0;
t[9][2]=55;
t[9][3]=0;
t[9][4]=6336;
t[9][5]=0;
t[9][6]=817991;
t[9][7]=0;
t[9][8]=108435745;
t[9][9]=0;
t[9][10]=479521663;
t[9][11]=0;
t[9][12]=528655152;
t[9][13]=0;
t[9][14]=764896039;
t[9][15]=0;
t[9][16]=416579196;
t[10][1]=1;
t[10][2]=89;
t[10][3]=571;
t[10][4]=18061;
t[10][5]=185921;
t[10][6]=4213133;
t[10][7]=53175517;
t[10][8]=31151234;
t[10][9]=479521663;
t[10][10]=584044562;
t[10][11]=472546535;
t[10][12]=732130620;
t[10][13]=186229290;
t[10][14]=274787842;
t[10][15]=732073997;
t[10][16]=320338127;
t[11][1]=0;
t[11][2]=144;
t[11][3]=0;
t[11][4]=51205;
t[11][5]=0;
t[11][6]=21001799;
t[11][7]=0;
t[11][8]=940739768;
t[11][9]=0;
t[11][10]=472546535;
t[11][11]=0;
t[11][12]=177126748;
t[11][13]=0;
t[11][14]=513673802;
t[11][15]=0;
t[11][16]=881924366;
t[12][1]=1;
t[12][2]=233;
t[12][3]=2131;
t[12][4]=145601;
t[12][5]=2332097;
t[12][6]=106912793;
t[12][7]=188978103;
t[12][8]=741005255;
t[12][9]=528655152;
t[12][10]=732130620;
t[12][11]=177126748;
t[12][12]=150536661;
t[12][13]=389322891;
t[12][14]=371114062;
t[12][15]=65334618;
t[12][16]=119004311;
t[13][1]=0;
t[13][2]=377;
t[13][3]=0;
t[13][4]=413351;
t[13][5]=0;
t[13][6]=536948224;
t[13][7]=0;
t[13][8]=164248716;
t[13][9]=0;
t[13][10]=186229290;
t[13][11]=0;
t[13][12]=389322891;
t[13][13]=0;
t[13][14]=351258337;
t[13][15]=0;
t[13][16]=144590622;
t[14][1]=1;
t[14][2]=610;
t[14][3]=7953;
t[14][4]=1174500;
t[14][5]=29253160;
t[14][6]=720246619;
t[14][7]=124166811;
t[14][8]=498190405;
t[14][9]=764896039;
t[14][10]=274787842;
t[14][11]=513673802;
t[14][12]=371114062;
t[14][13]=351258337;
t[14][14]=722065660;
t[14][15]=236847118;
t[14][16]=451896972;
t[15][1]=0;
t[15][2]=987;
t[15][3]=0;
t[15][4]=3335651;
t[15][5]=0;
t[15][6]=704300462;
t[15][7]=0;
t[15][8]=200052235;
t[15][9]=0;
t[15][10]=732073997;
t[15][11]=0;
t[15][12]=65334618;
t[15][13]=0;
t[15][14]=236847118;
t[15][15]=0;
t[15][16]=974417347;
t[16][1]=1;
t[16][2]=1597;
t[16][3]=29681;
t[16][4]=9475901;
t[16][5]=366944287;
t[16][6]=289288426;
t[16][7]=708175999;
t[16][8]=282756494;
t[16][9]=416579196;
t[16][10]=320338127;
t[16][11]=881924366;
t[16][12]=119004311;
t[16][13]=144590622;
t[16][14]=451896972;
t[16][15]=974417347;
t[16][16]=378503901;
}
ll solve(int n,int m)
{
ll ans=0;
for(int sta=0;sta<(1<<m-1);sta++)
{
int last=-1,num=0;
for(int j=0;j<m;j++)
if(sta&(1<<j))
l[num++]=j-last,last=j;
l[num++]=m-1-last;
for(int i=1;i<=n;i++)
{
for(int j=0;j<i;j++)
{
ll temp=1;
for(int k=0;k<num;k++)
temp=temp*t[i-j][l[k]]%mod;
if(!j)f[i]=temp;
else f[i]=((f[i]-f[j]*temp)%mod+mod)%mod;
}
}
if(num%2)ans=(ans+f[n])%mod;
else ans=((ans-f[n])%mod+mod)%mod;
}
return ans;
}
int main()
{
//init();
get_table();
int n,m;
while(~scanf("%d%d",&n,&m))
printf("%I64d\n",solve(n,m));
return 0;
}