九校联考-DL24凉心模拟Day1T3 三米诺 (tromino)
题目背景
金企鹅同学非常擅长用1*2的多米诺骨牌覆盖棋盘的题。有一天,正 在背四六级单词的他忽然想:既然两个格子的积木叫“多米诺(domino)”,那 么三个格子的的积木一定叫“三米诺(tromino)”了!用三米诺覆盖棋盘的题 怎么做呢?
题目描述
用三米诺覆盖3n 的矩形棋盘,共多少种方案?三米诺可旋转;两种 方案不同当且仅当这两种图案直接覆盖在一起无法重叠。
输入输出格式
输入格式:
一行一个整数n(n<=10^40000),表示棋盘列数。
输出格式:
一行一个整数,表示方案数,对998244353 取模。
输入输出样例
输入样例#1
2
输出样例#1
3
输入样例#2
3
输出样例#2
10
输入样例#3
29
输出样例#3
543450786
说明
对于10% 的数据,n <=5;
对于30% 的数据,n <=10^6;
对于40% 的数据,n <=20001000;
对于60% 的数据,n <=10^9;
对于80% 的数据,n <=10^1000
对于100% 的数据,n<=10^40000。
请在oeis搜索A134438数列并用矩阵,十进制快速幂优化
标程里的矩阵是手玩出来的...可能会写?
标程
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int tb[9][9] = {
{1, 2, 1, 1, 0, 0, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 1, 0, 0, 0},
{0, 1, 0, 0, 1, 0, 0, 0, 0},
};
const int N = 1000005, P = 998244353;
char s[N];
int n;
struct matrix {
ll g[9][9];
matrix(){
memset(g, 0, sizeof(g));
}
matrix operator * (const matrix &b) const {
matrix c;
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++)
for(int k = 0; k < 9; k++)
c.g[i][j] = (c.g[i][j] + g[i][k] * b.g[k][j]) % P;
return c;
}
} mtx, ans, tmp, pw[10];
int main(){
freopen("tromino.in","r",stdin);freopen("tromino.out","w",stdout);
scanf("%s", s);
n = strlen(s);
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++)
mtx.g[i][j] = tb[j][i];
for(int i = 0; i < 9; i++)
pw[0].g[i][i] = 1;
for(int i = 1; i <= 9; i++)
pw[i] = pw[i - 1] * mtx;
ans = pw[0];
for(int i = 0; i < n; i++){
tmp = ans = ans * ans;
ans = ans * ans;
ans = ans * ans * tmp * pw[s[i] - '0'];
}
printf("%lld\n", ans.g[0][0]);
return 0;
}