Jzoj4787 数格子

来源:互联网 发布:威廉.菲德内尔 知乎 编辑:程序博客网 时间:2024/05/16 10:16

题意:用1x2的骨牌填满4xN的格子的方案数

设f[i][j]表示填到第i行,这一行的状态为j的方案数

f[i][j]=Σf[i-1][k],其中k->j是一个合法转移

合法转移要满足两个条件:

1.若k的第x位为0,那么j的第x位一定要为1 (~k|j==j)

2.k,j都为一的位置必须是偶数个且必须连续,即k&j的二进制不能出现单独一个1,例如0101不合法,0011和0110都合法

这样就可以转移了,最后可以用矩阵加速

#include<stdio.h>#include<string.h>#define L long longconst int w[5]={0,3,6,12,15};int n,M;struct Mat{int n,m;int s[16][16];Mat(){ memset(s,0,sizeof s); }void clr(){ memset(s,0,sizeof s); }void set(int x,int y){ n=x; m=y; }Mat operator * (const Mat& b){Mat c; c.set(n,b.m);for(int i=0;i<n;++i)for(int j=0;j<b.m;++j)for(int k=0;k<m;++k)c.s[i][j]=(c.s[i][j]+(L)s[i][k]*b.s[k][j])%M;return c;}} a,b;bool ok(int x){for(int i=0;i<5;++i) if(x==w[i]) return 1;return 0;}void pow(int k){for(;k;b=b*b,k>>=1) if(k&1) a=a*b;}int main(){a.set(1,16); b.set(16,16);begin:a.clr(); b.clr();for(int i=0;i<16;++i)for(int j=0;j<16;++j)if(((~i&15)|j)==j&&ok(i&j)) b.s[i][j]=1;a.s[0][15]=1;scanf("%d%d",&n,&M);if(n&&M){pow(n);printf("%d\n",a.s[0][15]);goto begin;}}

原创粉丝点击