【多校】hdu 5731 Solid Dominoes Tilings 状压dp+容斥

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.
 

Input
The input file contains  m  and  n(1m,n16) .
 

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 13514
Hint
All 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);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值