题目描述
金企鹅同学非常擅长用 1 X 2 的多米诺骨牌覆盖棋盘的题。有一天,正在背四六级单词的他忽然想:既然两个格子的积木叫“多米诺 (domino)”,那么三个格子的的积木一定叫“三米诺 (tromino)”了!用三米诺覆盖棋盘的题怎么做呢?
用三米诺覆盖 3 X n 的矩形棋盘,共多少种方案?三米诺可旋转;两种方案不同当且仅当这两种图案直接覆盖在一起无法重叠。
例如 n = 2 时,共 3 种方案:
输入格式
一行一个整数 n(n ≤ 1040000 10 40000 ),表示棋盘列数。
输出格式
一行一个整数,表示方案数,对 998244353 取模。
样例数据
input1
2
output1
3
input2
3
output2
10
input3
29
output3
543450786
数据规模与约定
对于 10% 的数据,n ≤ 5;
对于 30% 的数据,n ≤ 106 10 6 ;
对于 40% 的数据,n ≤ 20001000;
对于 60% 的数据,n ≤ 109 10 9 ;
对于 80% 的数据,n ≤ 101000 10 1000 ;
对于 100% 的数据,n ≤ 1040000 10 40000 。
时间限制: 1s 1 s
空间限制: 512MB 512 MB
看着就像快速幂吧qaq
大力枚举一下转移的情况
可以写出方程
用个高斯消元或者直接用桶就可以了
消元后的方程
fi=fi−1+2∗fi−2+6∗fi−3+fi−4−fi−6
f
i
=
f
i
−
1
+
2
∗
f
i
−
2
+
6
∗
f
i
−
3
+
f
i
−
4
−
f
i
−
6
矩阵快速幂优化
最后40分?
十进制快速幂了解一下
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define M martix
const int p = 998244353;
struct martix{ll f[6][6];};
martix A;
M last;
char s[40010];
int n;
int read()
{
int sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(flag) return sum;
else return -sum;
}
void New(M &a)
{
rep(i,0,5)
rep(j,0,5)
if(i != j) a.f[i][j] = 0;
else a.f[i][j] = 1;
}
M mul(M a,M b,bool flag)
{
M ans;
for(int i = 0;i <= (flag?5:0);++i)
rep(j,0,5)
{
ans.f[i][j] = 0;
rep(k,0,5) ans.f[i][j] = (1ll*ans.f[i][j] + 1ll*a.f[i][k]*b.f[k][j]%p)%p;
}
return ans;
}
void pre()
{
#define F(i,j,k) A.f[i][j] = k;
F(0,0,1);F(1,0,2);F(2,0,6);F(3,0,1);F(5,0,p-1);
F(0,1,1);F(1,2,1);F(2,3,1);F(3,4,1);F(4,5,1);
}
M Pow(M a,int k)
{
M ans;New(ans);
while(k)
{
if(k & 1) ans = mul(ans,a,1);
a = mul(a,a,1);
k >>= 1;
}
return ans;
}
M PPow(M a)
{
M ans;New(ans);
repp(i,n,1)
{
if(s[i] != '0')
{
M tmp = Pow(a,s[i]-'0');
ans = mul(ans,tmp,1);
}
a = Pow(a,10);
}
return ans;
}
void work()
{
scanf("%s",s+1);
n = strlen(s+1);
if(n == 1 && s[1] == '1'){printf("1\n");exit(0);}
else if(n == 1 && s[1] == '2') {printf("3\n");exit(0);}
else if(n == 1 && s[1] == '3') {printf("10\n");exit(0);}
s[n] -= 3;
int i = n;while(s[i] < '0') s[i] += 10 , s[i-1] -= 1 , i--;
A = PPow(A);
last.f[0][0] = 10;last.f[0][1] = 3;last.f[0][2] = 1;
last.f[0][3] = 1;last.f[0][4] = 0;last.f[0][5] = 0;
last = mul(last,A,0);
printf("%d",last.f[0][0]);
}
int main()
{
freopen("tromino.in","r",stdin);
freopen("tromino.out","w",stdout);
pre();
work();
return 0;
}