HDU 5731 Solid Dominoes Tilings(轮廓线DP+容斥)

190 篇文章 1 订阅
1 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值