队内赛 T2DP矩阵乘法快速幂网格游走

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了队内赛 T2DP矩阵乘法快速幂网格游走相关的知识,希望对你有一定的参考价值。

网格游走

队内赛 T2 网格游走


题面

输入输出样例
输入 #1

2

输出 #1

17753229

输入 #2

23333

输出 #2

347338733


解题思路

先将9宫格拆成一条链

123
456
789
123456789

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} fi1,j,k+fi1,j,k1+fi1,j,k+1+fi1,j,k3+fi1,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算法 (转)

codevs1281 矩阵乘法 快速幂 !!!手写乘法取模!!! 练习struct的构造函数和成员函数

快速求斐波那契数列(矩阵乘法+快速幂)

模板——矩阵快速幂+矩阵乘法