九校聯考-DL24 涼心模擬 Day1T3 三米諾 (tromino)
阿新 • • 發佈:2018-12-14
題目描述
金企鵝同學非常擅長用 的多米諾骨牌覆蓋棋盤的題。有一天,正在背四六級單詞的他忽然想:既然兩個格子的積木叫“多米諾 (domino)”,那麼三個格子的的積木一定叫“三米諾 (tromino)”了!用三米諾覆蓋棋盤的題怎麼做呢?
用三米諾覆蓋 的矩形棋盤,共多少種方案?三米諾可旋轉;兩種方案不同當且僅當這兩種圖案直接覆蓋在一起無法重疊。
例如 時,共 種方案:
輸入輸出格式
輸入格式
一行一個整數 ,表示棋盤列數。
輸出格式
一行一個整數,表示方案數,對 取模。
輸入輸出樣例
輸入樣例#1:
2
輸出樣例#1:
3
輸入樣例#2:
3
輸出樣例#2:
10
輸入樣例#3:
29
輸出樣例#3:
543450786
解題分析
我們手玩一波樣例, 考慮新一行第行從前面某一行完整地轉移過來(即是兩個矩形拼接到一起的形式)
-
從行轉移:只可能是下面這種情況, 所以:
-
從第行轉移: 如果放豎著的可以歸納到行中, 我們不再計算。 於是有下面兩種情況:
然後我們發現似乎這個可以引出更多的轉移:
(對稱的並沒有畫出來)
類似這樣的我們同一歸到從行轉移中, 這樣我們可以維護一個記錄下標分別等於的答案的字首和。 這樣的話。
-
從第行轉移, 這樣可以引出這樣一類, 有四種同構:
即從行轉移, 這樣的話
我們發現似乎沒有用到, 於是再畫圖就可以發現有這樣一種情況:
當然這樣也會有對稱的情況, 但我們發現從轉移的情況也包含在了這個字首和裡面, 而它只能算一次, 所以我們最後需要減掉。
當然從轉移還有一種特殊情況:
這個單獨算上就好了。
最後的方程就是: 套上一個矩陣, 十進位制快速冪, 完美。
程式碼如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MOD 998244353
struct Matrix
{
ll mat[6][6];
void clear() {std::memset(mat, 0, sizeof(mat));}
}base, res, ans;
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
Matrix ret; ret.clear();
for (R int i = 0; i < 6; ++i)
for (R int j = 0; j < 6; ++j)
for (R int k = 0; k < 6; ++k)
ret.mat[i][k] = ret.mat[i][k] + 1ll * x.mat[i][j] * y.mat[j][k];
for (R int i = 0; i < 6; ++i)
for (R int j = 0; j < 6; ++j) ret.mat[i][j] %= MOD;
return ret;
}
char buf[40050];
int len;
IN void True_fpow(Matrix &tar, Matrix res, R int tm)
{
W (tm)
{
if(tm & 1) tar = tar * res;
res = res * res; tm >>= 1;
}
}
IN void fpow()
{
Matrix emp = base, unit = base;
for (R int i = len; i; --i)
{
True_fpow(base, res, buf[i] - '0');
unit = emp;
True_fpow(unit, res, 10);
res = unit;
}
}
void dealit()
{
R int pos = len;
if(buf[pos] >= '2') return buf[pos] -= 2, void();
--pos; W (buf[pos] == '0') --pos;
--buf[pos]; for (R int i = pos + 1; i < len; ++i) buf[i] = '9';
buf[len] += 8;
}
int main(void)
{
res = (Matrix){ -1, 0, 1, 4, 2, 2,//轉移矩陣
1, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1,
-1, 0, 1, 5, 2, 2};
base = (Matrix){1, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1};
//初始狀態
ans = (Matrix){ 3, 0, 0, 0, 0, 0,//dp[2]
1, 0, 0, 0, 0, 0,//dp[1]
1, 0, 0, 0, 0, 0,//dp[0]
1, 0, 0, 0, 0, 0,//sum[0]
1, 0, 0, 0, 0, 0,//sum[1]
3, 0, 0, 0, 0, 0};//sum[2]
scanf("%s", buf + 1); len = std::strlen(buf + 1);
if(len == 1 && buf[1] == '1') return puts("1"), 0;
if(len == 1 && buf[1] == '2') return puts("3"), 0;
dealit();
fpow();
printf("%d", ((base * ans).mat[0][0] + MOD) % MOD);
}