背景
还是一道水题
描述
在某个神秘的星球上有一个游乐园
游乐园里有一个奇怪的迷宫,迷宫内有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
*/