题目大意
有一辆车子,一开始行驶性能为0,每过1时间行驶性能就会提升1点。每个城市的道路都有性能要求。一开始位于1号城市,可以选择穿过一条城市间的路,也可以选择停留在一个城市不动,两个选择都花费1时间。只有车子的行驶性能大于等于一个城市时,车子才能到达该城市。求时间t时,位于城市n的路线方案数模10086后的值。
数据范围
节点数\(n\),\(m \leq 70\)
边数\(m\),\(m \leq 5000\)
时间\(t\),\(t \leq 10000000\)
第\(i\)个城市的性能要求\(h_i\),\(h_i \leq 70\)
分析
在开始有城市限制的时间内DP求方案数(已知\(h_i \leq 70\))。然后计算没有限制后,各城市之间可行路径的邻接矩阵。根据第70秒个城市方案数的结果计算第71秒各个城市之间路径的方案数。两矩阵相乘可以得到下一次的邻接矩阵。因此可以进行矩阵快速幂得到最终解。
复杂度\(O(70*m + n^3*log_2(t-70)) = O(n^3*log_2t)\)
算法
参考代码
#include <bits/stdc++.h>
using namespace std;
#define rg register
const int MAXN = 70 + 5;
const int MAXM = 5000 + 5;
const int MOD = 10086;
struct Matrix
{
int n, m, x[MAXN][MAXN];
Matrix()
{
memset(x, 0, sizeof x);
}
Matrix operator * (const Matrix a)
{
Matrix y;
y.n = a.n, y.m = a.m;
for(rg int i = 0; i < n; ++i)
for (rg int k = 0; k < m; ++k)
if(x[i][k])
for(rg int j = 0; j < a.m; ++j)
(y.x[i][j] += x[i][k] * a.x[k][j]) %= MOD;
return y;
}
}M, N;
struct Edge
{
int to, next;
}E[MAXM], E2[MAXM];
int n, m, t;
int A[MAXN];
int H[MAXN], H2[MAXN], cntE, cntE2;
inline void AddEdge(int u, int v)
{
E[++cntE] = (Edge){v, H[u]};
H[u] = cntE;
return ;
}
inline void AddEdge2(int u, int v)
{
E2[++cntE2] = (Edge){v, H2[u]};
H2[u] = cntE2;
return ;
}
void Input()
{
scanf("%d%d%d", &n, &m, &t);
++t;
for(rg int i = 0; i < n; ++i)
scanf("%d", &A[i]);
for(rg int i = 0, a, b; i < m; ++i)
{
scanf("%d%d", &a, &b);
AddEdge(a - 1, b - 1);
AddEdge2(b - 1, a - 1);
}
return ;
}
int F[MAXN][MAXN];
void Dp()
{
F[0][0] = 1;
for(rg int i = 1; i < min(t + 1, 71); ++i)
{
for(rg int j = 0; j < n; ++j)
{
F[i][j] = F[i - 1][j];
if(i <= A[j])
continue;
for(rg int e = H2[j]; e; e = E2[e].next)
(F[i][j] += F[i - 1][E2[e].to]) %= MOD;
}
}
if(t < 71)
{
printf("%d\n", F[t][n - 1]);
exit(0);
}
return ;
}
void InitMatrix()
{
M.n = M.m = N.n = N.m = n;
for(rg int i = 0; i < n; ++i)
{
N.x[i][i] = 1;
for(rg int j = H[i]; j; j = E[j].next)
++N.x[i][E[j].to];
}
for(rg int i = 0; i < n; ++i)
{
M.x[i][i] = F[70][i];
for(rg int j = H[i]; j; j = E[j].next)
(M.x[i][E[j].to] += F[70][i]) %= MOD;
}
return ;
}
void QuickPower(int times)
{
for(; times; times >>= 1)
{
if(times & 1)
M = M * N;
N = N * N;
}
int ans = 0;
for(rg int i = 0; i < n; ++i)
(ans += M.x[i][n - 1]) %= MOD;
printf("%d\n", ans);
return ;
}
int main()
{
Input();
Dp();
InitMatrix();
QuickPower(t - 71);
return 0;
}