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

本文探讨如何计算m×n矩形上使用2×1和1×2大小的多米诺骨牌进行稳定铺砌的方法。通过状态压缩动态规划解决铺砌数量问题,并运用容斥原理处理不同布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值