版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/83004715
Tromino
多米诺是
1×2的骨牌。tromino就是
1×3的骨牌(可以弯折),有两种基本形态(可以旋转):
公式
设
n个tromino完全覆盖
3×n矩形的方案数为
fn,则对于
n≥6存在递推式:
fn=fn−1+2fn−2+6fn−3+fn−4−fn−6
f0=1,f1=1,f2=3,f3=10,f4=23,f5=62。
推导
首先从
1×2的多米诺的递推公式说起:
设完全覆盖
2×n矩形的方案数为
gn,则对
n≥2存在递推式:
gn=gn−1+gn−2
g0=0,g1=1
简单推导如下:
假设当前已填满前
2×i块,考虑怎样填可以使得其增加任意
2×j块(
j≤n−i)。有两种最基本的覆盖方式:
之所以称为最基本的覆盖方式,是因为这两种结构是无法再进一步拆分的,而对于其他方式(如下图),都可以拆分成这二者。
所以求
gn时,它的最后一组基本排列方式只能二选一,所以
gn=gn−1+gn−2。
这样看来,对于tromino来说,只需要找出其所有的基本覆盖方式。
首先可以得到以下1+2+5=8种:
但是还有另外8种较难考虑到的情况:
所以可以得到:
fn=fn−1+2fn−2+5fn−3+(fn−4+fn−7+...)×2+(fn−5+fi−8+...)×2+(fn−6+fn−9+...)×4
而其中
(fn−4+fn−7+...)×2+(fn−5+fn−8+...)×2+(fn−6+fn−9+...)×4显然是一个分类前缀和的统计,可以由:
fn−3=fn−4+2fn−5+5fn−6+(fn−7+fn−10+...)×2+(fn−8+fn−11+...)×2+(fn−9+fn−12+...)×4
换元得到:
(fn−4+fn−7+...)×2+(fn−5+fn−8+...)×2+(fn−6+fn−9+...)×4=fn−3−fn−4−2fn−5−5fn−6+2fn−4+2fn−5+4fn−6
代回原式得到:
fn=fn−1+2fn−2+6fn−3+fn−4−fn−6
那么推导就结束了。
下面是求解n个tromino覆盖3*n矩形方案数的代码(矩阵+特征多项式优化):
#include<bits/stdc++.h>
#define RI register
using namespace std;
const int N=4e4+100,M=6,mod=998244353;
char s[N];
int n,a[14],re[14],ans;
struct P{int t[14];}nw,b;
int c[10]={0,1,2,6,1,0,998244352};
int as[13]={1,1,3,10,23,62,170,441,1173,3127};
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void Ml(int *a,int *b)
{
RI int i,j,val;
memset(re,0,sizeof(re));
for(i=0;i<7;++i)
for(j=0;j<7;++j)
re[i+j]=ad(re[i+j],mul(a[i],b[j]));
for(i=12;i>5;--i) if(re[i]){
val=re[i];
for(j=0;j<6;++j)
re[i-6+j]=ad(re[i-6+j],mul(val,c[6-j]));
re[i]=0;
}
for(i=0;i<=6;++i) a[i]=(re[i]+mod)%mod;
}
inline P fp(P a,int y)
{
memset(nw.t,0,sizeof(nw.t));
nw.t[0]=1;
for(;y;y>>=1,Ml(a.t,a.t))
if(y&1) Ml(nw.t,a.t);
return nw;
}
int main(){
RI int i,j;P res;
scanf("%s",s);
n=strlen(s);
reverse(s,s+n);
if(n==1) {printf("%d\n",as[s[0]-'0']);return 0;}
a[0]=b.t[1]=1;
for(i=0;i<n;++i){
if(s[i]!='0') {
res=fp(b,s[i]-'0');
Ml(a,res.t);
}
res=fp(b,10);
memcpy(b.t,res.t,sizeof(b.t));
}
for(i=0;i<6;++i) ans=ad(ans,mul(a[i],as[i]));
printf("%d\n",ans);
return 0;
}