Vijos-1603 迷宫 [矩阵快速幂]

Vijos /  题库 /


迷宫

背景

还是一道水题

描述

在某个神秘的星球上有一个游乐园
游乐园里有一个奇怪的迷宫,迷宫内有n个点,每个点之间都可能会有一条有向边(可能会有自环)
现在游乐园主有个问题想请你帮忙:
问:从s点走到f点,恰好走过m条边(边可以重复走),总共有多种不同的方案(两种方案只要有一条边不同,就是不同方案)
现在你只需要输出方案数对P取模的结果就可以了

格式

输入格式

一个整数n 
下面跟着n行n列的邻接矩阵,两个数之间有一个空格
在下一行依次是整数m,s,f,p

1<=n,s,f<=50
1<=m<=10^6 
1<=p<=10^5

输出格式

一个数即方案数对P取模的结果

样例1

样例输入1

5
0 1 1 1 1
0 0 0 0 0
1 1 0 1 1
0 0 0 0 1
0 0 0 0 1
3 1 5 1994

 
 

样例输出1

5

 
 

限制

各个测试点1s


朴素DP的话 可以写出如下方程

f[i][j][m] 表示从 i 到 j 走 m 步 的方案数

for 1 -> m  

for i = 1 -> n

for j = 1 -> n

for k = 1 -> n

if(map[j][k])

f[i][j][m] += f[i][k][m - 1] 

最后一行可以替换为 f[i][j][m] += f[i][k][m - 1] * map[k][j]

直观感受就是一个赤裸裸的矩阵快速幂

代码

#include <bits/stdc++.h>
using namespace std;

int n, m, s, f, p;

struct Mat
{
	int m[55][55];
	Mat operator * ( const Mat &a ) const
	{
		Mat tag;
		for(int i = 1; i <= n; ++i)
			for(int j = 1; j <= n; ++j)
			{
				tag.m[i][j] = 0;
				for(int k = 1; k <= n; ++k)
					(tag.m[i][j] += 1LL * m[i][k] * a.m[k][j] % p) %= p;
			}
		return tag;
	}
} ;

Mat MFP( Mat a, int b )
{
	Mat res;
	memset(res.m, 0, sizeof(res.m));
	for(int i = 1; i <= n; ++i)
		res.m[i][i] = 1;
	for(; b; b >>= 1, a = a * a)
		if(b & 1) res = res * a;
	return res;
}

int main()
{
	Mat base;
	cin >> n;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			scanf( "%d", &base.m[i][j] );
	cin >> m >> s >> f >> p;
	Mat ans = MFP(base, m);	
	cout << ans.m[s][f] % p << endl;
	return 0;
}
/*
5
0 1 1 1 1
0 0 0 0 0
1 1 0 1 1
0 0 0 0 1
0 0 0 0 1
3 1 5 1994
*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值