版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/84288049
洛谷传送门
BZOJ传送门
题目描述
windy在有向图中迷路了。 该有向图有 个节点,windy从节点 出发,他必须恰好在 时刻到达节点 。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
输入输出格式
输入格式:
第一行包含两个整数, 。 接下来有 行,每行一个长度为 的字符串。 第 行第 列为 表示从节点 到节点 没有边。 为 到 表示从节点 到节点 需要耗费的时间。
输出格式:
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以 的余数。
输入输出样例
输入样例#1:
2 2
11
00
输出样例#1:
1
输入样例#2:
5 30
12045
07105
47805
12024
12345
输出样例#2:
852
说明
【样例解释一】
0->0->1
【数据范围】
的数据,满足 ; 。
的数据,满足 ; 。
解题分析
如果是 矩阵, 直接举证快速幂就好了, 然而这道题有边权…
那就把每个点拆成 个, 暴力连边跑矩乘就好了。
代码如下:
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#define R register
#define MOD 2009
#define IN inline
#define W while
#define gc getchar()
#define MX 120
int n, bd;
long long T;
struct Matrix {int dat[MX][MX];} ans, mp;
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
Matrix ret;
std::memset(ret.dat, 0, sizeof(ret.dat));
for (R int i = 1; i <= bd; ++i)
for (R int j = 1; j <= bd; ++j)
for (R int k = 1; k <= bd; ++k)
ret.dat[i][j] = (ret.dat[i][j] + x.dat[i][k] * y.dat[k][j] % MOD) % MOD;
return ret;
}
IN void qpow()
{
for (R int i = 1; i <= bd; ++i) ans.dat[i][i] = 1;
W(T)
{
if(T & 1) ans = ans * mp;
mp = mp * mp, T >>= 1;
}
}
char buf[20];
int main(void)
{
scanf("%d%lld", &n, &T); bd = n * 9;
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= 8; ++j)
mp.dat[(i - 1) * 9 + j][(i - 1) * 9 + j + 1] = 1;
for (R int i = 1; i <= n; ++i)
{
scanf("%s", buf + 1);
for (R int j = 1; j <= n; ++j)
{
if(buf[j] != '0')
mp.dat[(i - 1) * 9 + buf[j] - '0'][(j - 1) * 9 + 1] = 1;
}
}
qpow();
printf("%d", ans.dat[1][n * 9 - 8]);
}