队内赛 T2DP矩阵乘法快速幂网格游走
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了队内赛 T2DP矩阵乘法快速幂网格游走相关的知识,希望对你有一定的参考价值。
队内赛 T2 网格游走
题面
输入输出样例
输入 #1
2
输出 #1
17753229
输入 #2
23333
输出 #2
347338733
解题思路
先将9宫格拆成一条链
1 | 2 | 3 |
---|---|---|
4 | 5 | 6 |
7 | 8 | 9 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 为在 i 时刻,机器人从起点 j 走到终点 k 的方案数
f
i
,
j
,
k
f_{i,j,k}
fi,j,k =
f
i
−
1
,
j
,
k
+
f
i
−
1
,
j
,
k
−
1
+
f
i
−
1
,
j
,
k
+
1
+
f
i
−
1
,
j
,
k
−
3
+
f
i
−
1
,
j
,
k
+
3
f_{i-1,j,k} + f_{i-1,j,k-1}+f_{i-1,j,k+1}+f_{i-1,j,k-3}+f_{i-1,j,k+3}
fi−1,j,k+fi−1,j,k−1+fi−1,j,k+1+fi−1,j,k−3+fi−1,j,k+3
当然这些 k-1 啥的还得判断有没有超界之类的
最后求一遍9的全排列,把答案累积起来
巴特,n * 9肯定得超时
考虑矩阵乘法
答案矩阵B的 B[i][j] 肯定得表示第 n 秒时,机器人从起点 i 走到终点 j 的方案数
初始化就是 B[i][i] = 1,表示第 0 秒每个格子都有一个机器人
再考虑转移矩阵A
B[i][] 和 A[][i]相乘(以下举例 i = 1)
那么 A[][1] 肯定是 1 能走的格子,1 能走到 1,2,4
[
1
.
.
.
1
.
.
.
0
.
.
.
1
.
.
.
0
.
.
.
0
.
.
.
0
.
.
.
0
.
.
.
0
.
.
.
]
\\begin{bmatrix} 1 &... \\\\ 1 & ...\\\\ 0 & ...\\\\ 1 & ...\\\\ 0 & ...\\\\ 0 & ...\\\\ 0 & ...\\\\ 0 & ...\\\\ 0 & ... \\end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡110100000...........................⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
依次列举求出A矩阵
然后 B * An 快速幂加速就好了
不开long long见祖宗
Code
#include <bits/stdc++.h>
#define ll unsigned long long
#define P 1000000007
using namespace std;
struct DT{
int n, m;
ll aed[10][10];
}A, B, ans;
ll n, answ;
int p[10], v[10];
DT operator *(DT A, DT B) {
DT C;
C.n = A.n, C.m = B.m;
memset(C.aed, 0, sizeof(C.aed));
for(int k = 1; k <= A.m; k ++)
for(int i = 1; i <= C.n; i ++)
for(int j = 1; j <= C.m; j ++)
C.aed[i][j] = (C.aed[i][j] + (A.aed[i][k] * B.aed[k][j]) % P) % P;
return C;
}
void init() {
A.n = A.m = B.n = B.m = 9;
for(int i = 1; i <= 9; i ++) {
A.aed[i][i] = 1, B.aed[i][i] = 1;
int j = i - 3; //上下行
if(j >= 1 && j <= 9) A.aed[j][i] = 1;
j = i + 3;
if(j >= 1 && j <= 9) A.aed[j][i] = 1;
j = i - 1; //左右,要判断是否在同一行
if((j - 1) / 3 == (i - 1) / 3 && j >= 1 && j <= 9) A.aed[j][i] = 1;
j = i + 1;
if((j - 1) / 3 == (i - 1) / 3 && j >= 1 && j <= 9) A.aed[j][i] = 1;
}
}
void ksm(ll x) {
if(x == 1) {
ans = A;
return;
}
ksm(x >> 1);
ans = ans * ans;
if(x & 1) ans = ans * A;
}
void dfs(int x) {
if(x > 9) {
ll ls = 1;
for(int i = 1; i <= 9; i ++)
ls = ls * B.aed[i][p[i]] % P; //暴搜9全排列,统计答案
answ = (answ + ls) % P;
return;
}
for(int i = 1; i <= 9; i ++)
if(!v[i]) {
p[x] = i, v[i] = 1;
dfs(x + 1);
v[i] = 0;
}
}
int main() {
scanf("%lld", &n);
init();
ksm(n);
B = B * ans;
dfs(1);
printf("%lld", answ);
}
以上是关于队内赛 T2DP矩阵乘法快速幂网格游走的主要内容,如果未能解决你的问题,请参考以下文章
整数快速乘法/快速幂+矩阵快速幂+Strassen算法 (转)