ABC236G
对于一个 \(p\times m\) 的矩阵 \(A\),与 \(m\times q\) 的矩阵 \(B\),定义广义矩阵乘法 \(A\times B=C\) 的结果是一个 \(p\times q\) 的矩阵 \(C\),满足:
\[C_{i,j}=(A_{i,1}\otimes B_{1,j})\oplus(A_{i,2}\otimes B_{2,j})\oplus\cdots\oplus(A_{i,n}\otimes B_{n,j})
\]
其中 \(\otimes\) 和 \(\oplus\) 是两种二元运算。
一些约定:
- \(\otimes\) 有交换律:\(a\otimes b=b\otimes a\)
- \(\otimes\) 有结合律:\((a\otimes b)\otimes c=a\otimes(b\otimes c)\)
- \(\otimes\) 对 \(\oplus\) 有分配律:\(a\otimes (b\oplus c)=(a\otimes b)\oplus (a\otimes c)\)
若 \(\otimes\) 有交换律,结合律,\(\otimes\) 对 \(\oplus\) 有分配律,那么广义的矩阵乘法就满足结合律。
下面证明 \(\otimes=\max,\oplus=\min\) 的广义矩阵乘法具有结合律:
首先显然 \(\max\) 有交换律和结合律,那么 \(\max(a,\min(b,c))=\min(\max(a,b),\max(a,c))\) 也是显然的。
回到原问题,令 \(f(v,i)\) 表示从 \(1\) 出发,经过 \(i\) 条边到达点 \(v\) 的最早时间,\(w(u,v)\) 表示边 \(u\to v\) 被加入的最小时间,可以得到转移:
\[f(v,i)=\min\limits_{1\le u\le n}\left\{\max(f(u,i-1),w(u,v))\right\}
\]
其中 \(f(1,0)=0\),其余均为 \(\infty\)。
不难发现这个由上面的结论可以矩阵快速幂优化:
\[\begin{bmatrix}
f(1,i)\\
f(2,i)\\
f(3,i)\\
\vdots \\
f(n,i)
\end{bmatrix}=\begin{bmatrix}
w(1,1), w(2,1),\cdots,w(n,1) \\
w(1,2), w(2,2),\cdots,w(n,2) \\
w(1,3), w(2,3),\cdots,w(n,3) \\
\ddots \\
w(1,n), w(2,n),\cdots,w(n,n)
\end{bmatrix}
\begin{bmatrix}
f(1,i-1)\\
f(2,i-1)\\
f(3,i-1)\\
\vdots \\
f(n,i-1)
\end{bmatrix}\]
时间复杂度 \(\mathcal O(n^3\log L)\)。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, inf = 0x3f3f3f3f;
int n, m, L;
struct mat {
int a[N][N];
mat operator * (const mat &x) const {
mat res; memset(res.a, 0x3f, sizeof res.a);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
for (int k = 1; k <= n; ++k)
res.a[i][j] = min(res.a[i][j], max(a[i][k], x.a[k][j]));
return res;
}
} f;
mat qpow(mat x, int y) {
mat res; memset(res.a, 0x3f, sizeof res.a);
for (int i = 1; i <= n; ++i) res.a[i][i] = 0;
while (y) {
if (y & 1) res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
int main() {
scanf("%d%d%d", &n, &m, &L);
memset(f.a, 0x3f, sizeof f.a);
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
f.a[u][v] = min(f.a[u][v], i);
}
f = qpow(f, L);
for (int i = 1; i <= n; ++i) printf("%d ", f.a[1][i] != inf ? f.a[1][i] : -1);
return 0;
}