Problem Description
Dominoes are rectangular tiles with nice 2 × 1 and 1 × 2 sizes.
The tiling is called solid if it is not possible to split the tiled rectangle by a straight line, not crossing the interior of any tile. For example, on the picture below the tilings (a) and (b) are solid, while the tilings (c) and (d) are not.
Now the managers of the company wonder, how many different solid tilings exist for an m × n rectangle. Help them to find that out.
The tiling is called solid if it is not possible to split the tiled rectangle by a straight line, not crossing the interior of any tile. For example, on the picture below the tilings (a) and (b) are solid, while the tilings (c) and (d) are not.
![](https://i-blog.csdnimg.cn/blog_migrate/7443862817f469706f61c163be920881.png)
Now the managers of the company wonder, how many different solid tilings exist for an m × n rectangle. Help them to find that out.
Input
The input file contains
m
and
n(1≤m,n≤16)
.
Output
Output one integer number
mod 1e9+7 - the number of solid tilings of m×n rectangle with 2 × 1 and 1 × 2 pavement tiles.
Sample Input
2 2 5 6 8 7
Sample Output
0 6 13514HintAll solid tilings for the 5×6 rectangle are provided on the picture below:![]()
题目分成两部分,第一部分求出无限制的覆盖情况,经典的状压dp,挑战程序设计中有详解。
之后进行容斥,枚举列的分割情况。然后在当前情况下,对行进行容斥,算出当前情况行无分割的情况。最后对列进行容斥,算出整体的情况。
具体实现的话要看代码才能明白。
#include <iostream>
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MOD=1e9+7;
ll d[18][18]={
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
,{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}
,{1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597}
,{1,0,3,0,11,0,41,0,153,0,571,0,2131,0,7953,0,29681}
,{1,1,5,11,36,95,281,781,2245,6336,18061,51205,145601,413351,1174500,3335651,9475901}
,{1,0,8,0,95,0,1183,0,14824,0,185921,0,2332097,0,29253160,0,366944287}
,{1,1,13,41,281,1183,6728,31529,167089,817991,4213133,21001799,106912793,536948224,720246619,704300462,289288426}
,{1,0,21,0,781,0,31529,0,1292697,0,53175517,0,188978103,0,124166811,0,708175999}
,{1,1,34,153,2245,14824,167089,1292697,12988816,108435745,31151234,940739768,741005255,164248716,498190405,200052235,282756494}
,{1,0,55,0,6336,0,817991,0,108435745,0,479521663,0,528655152,0,764896039,0,416579196}
,{1,1,89,571,18061,185921,4213133,53175517,31151234,479521663,584044562,472546535,732130620,186229290,274787842,732073997,320338127}
,{1,0,144,0,51205,0,21001799,0,940739768,0,472546535,0,177126748,0,513673802,0,881924366}
,{1,1,233,2131,145601,2332097,106912793,188978103,741005255,528655152,732130620,177126748,150536661,389322891,371114062,65334618,119004311}
,{1,0,377,0,413351,0,536948224,0,164248716,0,186229290,0,389322891,0,351258337,0,144590622}
,{1,1,610,7953,1174500,29253160,720246619,124166811,498190405,764896039,274787842,513673802,371114062,351258337,722065660,236847118,451896972}
,{1,0,987,0,3335651,0,704300462,0,200052235,0,732073997,0,65334618,0,236847118,0,974417347}
,{1,1,1597,29681,9475901,366944287,289288426,708175999,282756494,416579196,320338127,881924366,119004311,144590622,451896972,974417347,378503901}
};
int v[22],n,m;
ll tmp[22],f[22];
int main()
{
while(~scanf("%d%d",&n,&m))
{
int ed=1<<m-1;
ll ans=0;
for(int i=0;i<ed;i++)
{
int cnt=0,last=-1;
for(int j=0;j<m-1;j++)
{
if((i>>j)&1)
{
v[cnt++]=j-last;
last=j;
}
}
v[cnt++]=m-1-last;
for(int j=1;j<=n;j++)
{
tmp[j]=1;
for(int k=0;k<cnt;k++) tmp[j]=tmp[j]*d[j][v[k]]%MOD;//tmp记录当前列情况下,j行无限制的数量
}
for(int j=1;j<=n;j++)
for(int k=0;k<j;k++)
{
if(k==0) f[j]=tmp[j];
else f[j]=(f[j]-f[k]*tmp[j-k]+MOD)%MOD;//对行容斥,f记录当前列情况下,j行无分割的数量
}
if(cnt&1) ans=(ans+f[n])%MOD;//对列容斥
else ans=(ans-f[n]+MOD)%MOD;
}
printf("%lld\n",ans);
}
}