[题意]
用1*2的多米诺骨牌完美覆盖n*m的网格,且不存在水平或竖直分割线,求方法数
[分析]
若没有分割线的限制,则此题变为了轮廓线DP入门题POJ 2411
加入了限制条件后,则要减去不合法的情况。但分割线的组合很多,所以考虑用容斥定理,加加减减。。。
初步想法:
将无限制的算法稍加修改(行转移时,不转移排满的情况),则得到了无行分割线的方案数
枚举列分割线,使用容斥定理统计答案
发现问题:
当确定列分割线后,把原网格分为了几个部分,使用乘法原理将他们不含行分割线的方案乘起来。
但事实上,可以允许某些部分含有行分割线,而整体却不含,统计时漏掉了这部分方案
改进:
确定了列分割线后,逐行递推地计算在当前列分割下,不含行分割线的方案数
设dp[i]为在当前列分割下,1~i行无行分割线的方案数
则dp[i]可以由dp[1]~dp[i-1]递推
公式为
dp[i]=g[i]−∑i−1j=1dp[i−j]∗g[j]
其中g[j]为在当前列分割下,1-j行无行限制的方案数,对与两条相邻分割线(包括边界线)内的部分,本质上就是无任何限制的完美覆盖,可以预处理出来,各个部分用乘法原理全部乘起来即可
枚举列分割线的所有
2m−1
种选择,根据线的条数奇加偶减的统计即可
可能本弱写的丑,直接预处理无任何限制的方案会TLE,这里打表通过了。
[代码]
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int mod = 1e9 + 7 ;
const int N = 17 ;
int n , m , t ;
LL dp[2][(1<<16)+5] ;
LL cnt[N][N] ;
void init()
{
cnt[1][1] = cnt[1][1] = 0 ;
cnt[2][1] = cnt[1][2] = 1 ;
cnt[2][2] = cnt[2][2] = 2 ;
cnt[3][1] = cnt[1][3] = 0 ;
cnt[3][2] = cnt[2][3] = 3 ;
cnt[3][3] = cnt[3][3] = 0 ;
cnt[4][1] = cnt[1][4] = 1 ;
cnt[4][2] = cnt[2][4] = 5 ;
cnt[4][3] = cnt[3][4] = 11 ;
cnt[4][4] = cnt[4][4] = 36 ;
cnt[5][1] = cnt[1][5] = 0 ;
cnt[5][2] = cnt[2][5] = 8 ;
cnt[5][3] = cnt[3][5] = 0 ;
cnt[5][4] = cnt[4][5] = 95 ;
cnt[5][5] = cnt[5][5] = 0 ;
cnt[6][1] = cnt[1][6] = 1 ;
cnt[6][2] = cnt[2][6] = 13 ;
cnt[6][3] = cnt[3][6] = 41 ;
cnt[6][4] = cnt[4][6] = 281 ;
cnt[6][5] = cnt[5][6] = 1183 ;
cnt[6][6] = cnt[6][6] = 6728 ;
cnt[7][1] = cnt[1][7] = 0 ;
cnt[7][2] = cnt[2][7] = 21 ;
cnt[7][3] = cnt[3][7] = 0 ;
cnt[7][4] = cnt[4][7] = 781 ;
cnt[7][5] = cnt[5][7] = 0 ;
cnt[7][6] = cnt[6][7] = 31529 ;
cnt[7][7] = cnt[7][7] = 0 ;
cnt[8][1] = cnt[1][8] = 1 ;
cnt[8][2] = cnt[2][8] = 34 ;
cnt[8][3] = cnt[3][8] = 153 ;
cnt[8][4] = cnt[4][8] = 2245 ;
cnt[8][5] = cnt[5][8] = 14824 ;
cnt[8][6] = cnt[6][8] = 167089 ;
cnt[8][7] = cnt[7][8] = 1292697 ;
cnt[8][8] = cnt[8][8] = 12988816 ;
cnt[9][1] = cnt[1][9] = 0 ;
cnt[9][2] = cnt[2][9] = 55 ;
cnt[9][3] = cnt[3][9] = 0 ;
cnt[9][4] = cnt[4][9] = 6336 ;
cnt[9][5] = cnt[5][9] = 0 ;
cnt[9][6] = cnt[6][9] = 817991 ;
cnt[9][7] = cnt[7][9] = 0 ;
cnt[9][8] = cnt[8][9] = 108435745 ;
cnt[9][9] = cnt[9][9] = 0 ;
cnt[10][1] = cnt[1][10] = 1 ;
cnt[10][2] = cnt[2][10] = 89 ;
cnt[10][3] = cnt[3][10] = 571 ;
cnt[10][4] = cnt[4][10] = 18061 ;
cnt[10][5] = cnt[5][10] = 185921 ;
cnt[10][6] = cnt[6][10] = 4213133 ;
cnt[10][7] = cnt[7][10] = 53175517 ;
cnt[10][8] = cnt[8][10] = 31151234 ;
cnt[10][9] = cnt[9][10] = 479521663 ;
cnt[10][10] = cnt[10][10] = 584044562 ;
cnt[11][1] = cnt[1][11] = 0 ;
cnt[11][2] = cnt[2][11] = 144 ;
cnt[11][3] = cnt[3][11] = 0 ;
cnt[11][4] = cnt[4][11] = 51205 ;
cnt[11][5] = cnt[5][11] = 0 ;
cnt[11][6] = cnt[6][11] = 21001799 ;
cnt[11][7] = cnt[7][11] = 0 ;
cnt[11][8] = cnt[8][11] = 940739768 ;
cnt[11][9] = cnt[9][11] = 0 ;
cnt[11][10] = cnt[10][11] = 472546535 ;
cnt[11][11] = cnt[11][11] = 0 ;
cnt[12][1] = cnt[1][12] = 1 ;
cnt[12][2] = cnt[2][12] = 233 ;
cnt[12][3] = cnt[3][12] = 2131 ;
cnt[12][4] = cnt[4][12] = 145601 ;
cnt[12][5] = cnt[5][12] = 2332097 ;
cnt[12][6] = cnt[6][12] = 106912793 ;
cnt[12][7] = cnt[7][12] = 188978103 ;
cnt[12][8] = cnt[8][12] = 741005255 ;
cnt[12][9] = cnt[9][12] = 528655152 ;
cnt[12][10] = cnt[10][12] = 732130620 ;
cnt[12][11] = cnt[11][12] = 177126748 ;
cnt[12][12] = cnt[12][12] = 150536661 ;
cnt[13][1] = cnt[1][13] = 0 ;
cnt[13][2] = cnt[2][13] = 377 ;
cnt[13][3] = cnt[3][13] = 0 ;
cnt[13][4] = cnt[4][13] = 413351 ;
cnt[13][5] = cnt[5][13] = 0 ;
cnt[13][6] = cnt[6][13] = 536948224 ;
cnt[13][7] = cnt[7][13] = 0 ;
cnt[13][8] = cnt[8][13] = 164248716 ;
cnt[13][9] = cnt[9][13] = 0 ;
cnt[13][10] = cnt[10][13] = 186229290 ;
cnt[13][11] = cnt[11][13] = 0 ;
cnt[13][12] = cnt[12][13] = 389322891 ;
cnt[13][13] = cnt[13][13] = 0 ;
cnt[14][1] = cnt[1][14] = 1 ;
cnt[14][2] = cnt[2][14] = 610 ;
cnt[14][3] = cnt[3][14] = 7953 ;
cnt[14][4] = cnt[4][14] = 1174500 ;
cnt[14][5] = cnt[5][14] = 29253160 ;
cnt[14][6] = cnt[6][14] = 720246619 ;
cnt[14][7] = cnt[7][14] = 124166811 ;
cnt[14][8] = cnt[8][14] = 498190405 ;
cnt[14][9] = cnt[9][14] = 764896039 ;
cnt[14][10] = cnt[10][14] = 274787842 ;
cnt[14][11] = cnt[11][14] = 513673802 ;
cnt[14][12] = cnt[12][14] = 371114062 ;
cnt[14][13] = cnt[13][14] = 351258337 ;
cnt[14][14] = cnt[14][14] = 722065660 ;
cnt[15][1] = cnt[1][15] = 0 ;
cnt[15][2] = cnt[2][15] = 987 ;
cnt[15][3] = cnt[3][15] = 0 ;
cnt[15][4] = cnt[4][15] = 3335651 ;
cnt[15][5] = cnt[5][15] = 0 ;
cnt[15][6] = cnt[6][15] = 704300462 ;
cnt[15][7] = cnt[7][15] = 0 ;
cnt[15][8] = cnt[8][15] = 200052235 ;
cnt[15][9] = cnt[9][15] = 0 ;
cnt[15][10] = cnt[10][15] = 732073997 ;
cnt[15][11] = cnt[11][15] = 0 ;
cnt[15][12] = cnt[12][15] = 65334618 ;
cnt[15][13] = cnt[13][15] = 0 ;
cnt[15][14] = cnt[14][15] = 236847118 ;
cnt[15][15] = cnt[15][15] = 0 ;
cnt[16][1] = cnt[1][16] = 1 ;
cnt[16][2] = cnt[2][16] = 1597 ;
cnt[16][3] = cnt[3][16] = 29681 ;
cnt[16][4] = cnt[4][16] = 9475901 ;
cnt[16][5] = cnt[5][16] = 366944287 ;
cnt[16][6] = cnt[6][16] = 289288426 ;
cnt[16][7] = cnt[7][16] = 708175999 ;
cnt[16][8] = cnt[8][16] = 282756494 ;
cnt[16][9] = cnt[9][16] = 416579196 ;
cnt[16][10] = cnt[10][16] = 320338127 ;
cnt[16][11] = cnt[11][16] = 881924366 ;
cnt[16][12] = cnt[12][16] = 119004311 ;
cnt[16][13] = cnt[13][16] = 144590622 ;
cnt[16][14] = cnt[14][16] = 451896972 ;
cnt[16][15] = cnt[15][16] = 974417347 ;
cnt[16][16] = cnt[16][16] = 378503901 ;
}
void update( int a , int b )
{
if( b&(1<<m) )
( dp[!t][b^(1<<m)] += dp[t][a] ) %= mod ;
}
void cal( )
{
int e = (1<<m)-1 ; t = 0 ;
memset(dp,0,sizeof dp) ;
dp[t][e] = 1 ;
for( int i = 0 ; i < n ; i++ )
{
for( int j = 0 ; j < m ; j++ )
{
memset(dp[!t],0,sizeof(dp[!t])) ;
for( int k = 0 ; k <= e ; k++ )
{
update(k,k<<1) ;
if( i && ~k&(1<<m-1) ) update(k,(k<<1)^(1<<m)^1) ;
if( j && ~k&1 ) update(k,(k<<1)^3) ;
}
t = !t ;
}
}
cnt[n][m] = cnt[m][n] = dp[t][e] ;
printf( "cnt[%d][%d] = cnt[%d][%d] = %I64d ;\n" , n , m , m , n , cnt[n][m]%mod ) ;
}
LL DP( int n , int m )
{
LL dp[N] , res = 0 ;
int bit[N] , k ;
for( int s = 0 ; s < 1<<(m-1) ; s++ )
{
bit[k=0] = -1 ;
for( int i = 0 ; i < m-1 ; i++ )
if( s&(1<<i) )
bit[++k] = i ;
bit[++k] = m-1 ;
for( int i = 1 ; i <= n ; i++ )
{
for( int j = 0 ; j < i ; j++ )
{
LL tot = 1 ;
for( int p = 0 ; p < k ; p++ )
tot = tot*cnt[i-j][bit[p+1]-bit[p]]%mod ;
dp[i] = j ? ( dp[i] - tot*dp[j]%mod + mod ) % mod : tot ;
}
}
if( ~k&1 ) res = ( res - dp[n] + mod ) % mod ;
else res = ( res + dp[n] ) % mod ;
}
return res ;
}
int main()
{
/*
for( n = 1 ; n <= 16 ; n++ )
for( m = 1 ; m <= n ; m++ )
cal() ;
*/
init() ;
while( ~scanf( "%d%d" , &n , &m ) )
{
if( n < m ) swap(n,m) ;
printf( "%d\n" , DP(n,m) ) ;
}
return 0 ;
}
既然都打表了,那干脆把ans也打个表刷个0ms吧,233
这里把答案表贴出来供小伙伴们对拍吧~
ans[1][1] = 0 ;
ans[2][1] = 1 ;
ans[2][2] = 0 ;
ans[3][1] = 0 ;
ans[3][2] = 0 ;
ans[3][3] = 0 ;
ans[4][1] = 0 ;
ans[4][2] = 0 ;
ans[4][3] = 0 ;
ans[4][4] = 0 ;
ans[5][1] = 0 ;
ans[5][2] = 0 ;
ans[5][3] = 0 ;
ans[5][4] = 0 ;
ans[5][5] = 0 ;
ans[6][1] = 0 ;
ans[6][2] = 0 ;
ans[6][3] = 0 ;
ans[6][4] = 0 ;
ans[6][5] = 6 ;
ans[6][6] = 0 ;
ans[7][1] = 0 ;
ans[7][2] = 0 ;
ans[7][3] = 0 ;
ans[7][4] = 0 ;
ans[7][5] = 0 ;
ans[7][6] = 124 ;
ans[7][7] = 0 ;
ans[8][1] = 0 ;
ans[8][2] = 0 ;
ans[8][3] = 0 ;
ans[8][4] = 0 ;
ans[8][5] = 108 ;
ans[8][6] = 62 ;
ans[8][7] = 13514 ;
ans[8][8] = 25506 ;
ans[9][1] = 0 ;
ans[9][2] = 0 ;
ans[9][3] = 0 ;
ans[9][4] = 0 ;
ans[9][5] = 0 ;
ans[9][6] = 1646 ;
ans[9][7] = 0 ;
ans[9][8] = 991186 ;
ans[9][9] = 0 ;
ans[10][1] = 0 ;
ans[10][2] = 0 ;
ans[10][3] = 0 ;
ans[10][4] = 0 ;
ans[10][5] = 1182 ;
ans[10][6] = 1630 ;
ans[10][7] = 765182 ;
ans[10][8] = 3103578 ;
ans[10][9] = 262834138 ;
ans[10][10] = 759280991 ;
ans[11][1] = 0 ;
ans[11][2] = 0 ;
ans[11][3] = 0 ;
ans[11][4] = 0 ;
ans[11][5] = 0 ;
ans[11][6] = 18120 ;
ans[11][7] = 0 ;
ans[11][8] = 57718190 ;
ans[11][9] = 0 ;
ans[11][10] = 264577134 ;
ans[11][11] = 0 ;
ans[12][1] = 0 ;
ans[12][2] = 0 ;
ans[12][3] = 0 ;
ans[12][4] = 0 ;
ans[12][5] = 10338 ;
ans[12][6] = 25654 ;
ans[12][7] = 32046702 ;
ans[12][8] = 238225406 ;
ans[12][9] = 462717719 ;
ans[12][10] = 712492587 ;
ans[12][11] = 759141342 ;
ans[12][12] = 398579168 ;
ans[13][1] = 0 ;
ans[13][2] = 0 ;
ans[13][3] = 0 ;
ans[13][4] = 0 ;
ans[13][5] = 0 ;
ans[13][6] = 180288 ;
ans[13][7] = 0 ;
ans[13][8] = 965022920 ;
ans[13][9] = 0 ;
ans[13][10] = 886997066 ;
ans[13][11] = 0 ;
ans[13][12] = 83006813 ;
ans[13][13] = 0 ;
ans[14][1] = 0 ;
ans[14][2] = 0 ;
ans[14][3] = 0 ;
ans[14][4] = 0 ;
ans[14][5] = 79818 ;
ans[14][6] = 317338 ;
ans[14][7] = 136189727 ;
ans[14][8] = 388537910 ;
ans[14][9] = 560132342 ;
ans[14][10] = 577689269 ;
ans[14][11] = 567660301 ;
ans[14][12] = 821419653 ;
ans[14][13] = 690415372 ;
ans[14][14] = 796514774 ;
ans[15][1] = 0 ;
ans[15][2] = 0 ;
ans[15][3] = 0 ;
ans[15][4] = 0 ;
ans[15][5] = 0 ;
ans[15][6] = 1684956 ;
ans[15][7] = 0 ;
ans[15][8] = 937145938 ;
ans[15][9] = 0 ;
ans[15][10] = 510014880 ;
ans[15][11] = 0 ;
ans[15][12] = 942235780 ;
ans[15][13] = 0 ;
ans[15][14] = 696587391 ;
ans[15][15] = 0 ;
ans[16][1] = 0 ;
ans[16][2] = 0 ;
ans[16][3] = 0 ;
ans[16][4] = 0 ;
ans[16][5] = 570342 ;
ans[16][6] = 3416994 ;
ans[16][7] = 378354090 ;
ans[16][8] = 315565230 ;
ans[16][9] = 699538539 ;
ans[16][10] = 807555438 ;
ans[16][11] = 47051173 ;
ans[16][12] = 558077885 ;
ans[16][13] = 620388364 ;
ans[16][14] = 175421667 ;
ans[16][15] = 856463275 ;
ans[16][16] = 341279366 ;