网格游走【矩阵快速幂】【DP】

>Link

luogu T202676


>Description

在这里插入图片描述
n ≤ 1 0 18 n\le10^{18} n1018


>解题思路

感觉就是自己脑子有坑QwQ 考场想到了矩阵快速幂然后伞兵了又觉得加速不了(…)然后就交了个DP上去QwQ 我就是菜

搞一个DP,设 f S , i , j f_{S,i,j} fS,i,j 为起点为 S S S,第 i i i秒到 j j j的方案数
然后预处理+矩阵快速幂加速,爆搜出每个点最终到的地方,累计答案就行了


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 100010
using namespace std;

const int xx[4] = {
    
    -1, 0, 0, 1}, yy[4] = {
    
    0, -1, 1, 0};
const LL Mod = 1e9 + 7;
struct matrix
{
    
    
	int x, y;
	LL a[15][15];
} A, B, ans;
int p[15][15], w[15];
LL n, sum, ANS, f[15][15];
bool use[15];

int getnum (int x, int y) {
    
    return (x - 1) * 3 + y;}
matrix operator * (matrix a, matrix b)
{
    
    
	matrix c;
	c.x = a.x, c.y = b.y;
	for (int i = 1; i <= c.x; i++)
	  for (int j = 1; j <= c.y; j++) c.a[i][j] = 0;
	for (int i = 1; i <= c.x; i++)
	  for (int j = 1; j <= c.y; j++)
	    for (int k = 1; k <= a.y; k++)
	      c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j] % Mod) % Mod;
	return c;
}
void power (LL k)
{
    
    
	if (k == 1) {
    
    B = A; return;}
	power (k >> 1);
	B = B * B;
	if (k & 1) B = B * A;
}
LL solve (int S, int T)
{
    
    
	ans.x = 1, ans.y = 9;
	for (int i = 1; i <= 9; i++) ans.a[1][i] = 0;
	ans.a[1][S] = 1;
	ans = ans * B;
	return ans.a[1][T];
}
void dfs (int now)
{
    
    
	if (now > 9)
	{
    
    
		sum = 1;
		for (int i = 1; i <= 9; i++)
		  sum = sum * f[i][w[i]] % Mod;
		ANS = (ANS + sum) % Mod;
		return;
	}
	for (int i = 1; i <= 9; i++)
	  if (!use[i])
	  {
    
    
	  	use[i] = 1;
	  	w[now] = i;
	  	dfs (now + 1);
	  	w[now] = 0;
	  	use[i] = 0;
	  }
}

int main()
{
    
    
	scanf ("%lld", &n);
	int tx, ty, num;
	for (int x = 1; x <= 3; x++)
	  for (int y = 1; y <= 3; y++)
	  {
    
    
	  	num = getnum (x, y);
	  	for (int i = 0; i < 4; i++)
	  	{
    
    
	  		tx = x + xx[i], ty = y + yy[i];
	  		if (tx < 1 || tx > 3 || ty < 1 || ty > 3) continue;
	  		p[num][getnum (tx, ty)] = 1;
		}
		p[num][num] = 1;
	  }
	A.x = A.y = 9;
	for (int i = 1; i <= 9; i++)
	  for (int j = 1; j <= 9; j++)
	    A.a[j][i] = p[i][j];
	power (n);
	for (int i = 1; i <= 9; i++)
	  for (int j = 1; j <= 9; j++)
	    f[i][j] = solve (i, j);
	dfs (1);
	printf ("%lld", ANS);
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_43010386/article/details/121093954