[2018.10.10 T3] 三米诺

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83029868

暂无链接

三米诺

题目背景

金企鹅同学非常擅长用 1 × 2 1 × 2 的多米诺骨牌覆盖棋盘的题。有一天,正在背四六级单词的他忽然想:既然两个格子的积木叫“多米诺 (domino)”,那么三个格子的的积木一定叫“三米诺 (tromino)”了!用三米诺覆盖棋盘的题怎么做呢?

题目描述

用三米诺覆盖 3 × n 3 × n 的矩形棋盘,共多少种方案?三米诺可旋转;两种方案不同当且仅当这两种图案直接覆盖在一起无法重叠。

例如 n = 2 n = 2 时,共 3 3 种方案:

1.png

3 × 2 用三米诺覆盖3\times 2棋盘

格式
输入格式

一行一个整数 n ( n 1 0 40000 ) n(n ≤ 10^{40000}) ,表示棋盘列数。

输出格式

一行一个整数,表示方案数,对 998244353 998244353 取模。

样例
样例 1 输入

2

样例 1 输出

3

样例 2 输入

3

扫描二维码关注公众号,回复: 3638873 查看本文章
样例 2 输出

10

样例 3 输入

29

样例 3 输出

543450786

数据范围

对于 10 % 10\% 的数据, n 5 n ≤ 5
对于 30 % 30\% 的数据, n 1 0 6 n ≤ 10^6
对于 40 % 40\% 的数据, n 20001000 n ≤ 20001000
对于 60 % 60\% 的数据, n 1 0 9 n ≤ 10^9
对于 80 % 80\% 的数据, n 1 0 1000 n ≤ 10^{1000}
对于 100 % 100\% 的数据, n 1 0 40000 n ≤ 10^{40000}

题解

借鉴多米诺的思路,我们很容易想到长度为 1 , 2 , 3 1,2,3 的转移,然而三米诺的精髓在于存在弯折的形状,这使三米诺可以将几个长条错起来放,不需要像多米诺一样长条必须并排放置。

于是出现了下面三种奇妙的转移:
1.png
2.png
3.png

你会发现它们都是可以无限延伸且不重不漏的,要 d p dp 统计答案的话,可能是 O ( n 2 ) O(n^2) 的。。。

这个时候你可以暴力算前几项,然后 上OEIS通过高斯消元把递推系数解出来,得到正确的递推式:

4.png
论一个熟练的OEISer如何快速AC此题。

神犇 R o c k u d \mathcal{Rockud} 还有一个牛逼哄哄的维护了三个前缀和的递推做法,作为蒟蒻只能 % % % \%\%\%

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=4e5,N=6,mod=998244353;
struct sd{ll sq[N+2][N+2];}c,one,base,ans,ni,r;
int mat[N+1][N+1]={0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,0,1,0,0,0,0,6,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,-1,0,0,0,0,0};
int fan[N+1][N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,1,0,0,0,0,1,0,0,1,0,0,0,2,0,0,0,1,0,0,6,0,0,0,0,1,0,1,0,0,0,0,0,1,0};
int f[]={1,1,3,10,23,62,170};
ll AC,len;
char num[M];
sd operator*(sd a,sd b){for(int i=1,j,k;i<=N;++i)for(j=1;j<=N;++j)for(c.sq[i][j]=0,k=1;k<=N;++k)(c.sq[i][j]+=a.sq[i][k]*b.sq[k][j]%mod)%=mod;return c;}
sd power(sd a,int p){for(r=one;p;p>>=1,a=a*a)if(p&1)r=r*a;return r;}
void in(){scanf("%s",num+1);}
void ac()
{
	if((len=strlen(num+1))==1&&num[1]-'0'<=6){printf("%d",f[num[1]-'0']);return;}
	for(int i=1;i<=N;++i)ans.sq[i][i]=one.sq[i][i]=1;
	for(int i=1;i<=N;++i)for(int j=1;j<=N;++j)base.sq[i][j]=mat[i][j],ni.sq[i][j]=fan[i][j];
	for(int i=len;i;--i)ans=ans*power(base,num[i]-'0'),base=power(base,10);
	ans=ans*power(ni,6);
	for(int i=1;i<=N;++i)(AC+=ans.sq[i][1]*f[N-i+1]%mod)%=mod;
	printf("%lld\n",(AC+mod)%mod);
}
int main(){in(),ac();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/83029868
T3
今日推荐