题解
由于所求时间t过大不能采用直接递推的方式,使用矩阵快速幂来加快递推速度复杂度降低为O((n*10)^3logt)
令d[code(i, j)]表示i秒前j节点的方案数,最多存储10秒,code为编码函数
定义转移矩阵tran,因为每次乘上转移矩阵要将当前时间后推1秒所以tran[code(i, j)][code(i + 1. j)]=1表示每个节点由当前时间转移到下一秒的时间,i表示时间j表示节点编号
对于题目所给边(i, j, c)表示从i节点走到j节点花费c秒,则tran[code(c-1, i)][code(0, j)]=1表示从c秒前转移到现在时刻,-1是因为每次乘上转移矩阵要后推一秒时间
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 110;
const int MOD = 2009;
struct Matrix
{
ll m[MAXN][MAXN];
static const int N = 100; //阶数
Matrix(int v = 0)
{
memset(m, 0, sizeof(m));
if (v)
for (int i = 0; i < N; i++)
m[i][i] = v;
}
Matrix operator * (const Matrix &b)
{
Matrix t;
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
t.m[i][j] = (t.m[i][j] + m[i][k] * b.m[k][j]) % MOD;
return t;
}
friend Matrix operator ^ (Matrix a, int n)
{
Matrix t(1);
while (n)
{
if (n & 1)
t = t * a;
a = a * a;
n >>= 1;
}
return t;
}
}tran, a; //a[0][code(i, j)]表示i秒前j节点的方案数 最多存储10秒
int code(int t, int x) //编码t秒x节点
{
return t * 10 + x;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n, t;
cin >> n >> t;
for (int i = 0; i < n; i++)
{
char c;
for (int j = 0; j < n; j++)
{
scanf(" %c", &c);
c -= '0';
if (c)
tran.m[code(c - 1, i)][code(0, j)] = 1; //c秒前的i转移到0现在时刻的j -1是因为转移后推1秒时间
}
}
a.m[0][0] = 1; //起点为1
for (int i = 0; i < 9; i++)
for (int j = 0; j < n; j++)
tran.m[code(i, j)][code(i + 1, j)] = 1; //每次转移 当前位置转移到1秒前的状态
a = a * (tran ^ t);
cout << a.m[0][n - 1] << endl;
return 0;
}