E - 魔法の道 / Magic Road 解説 by admin 印刷ページ
Claude 4.6 Opus (Thinking)Overview
This problem asks us to find, over all paths from city \(1\) to city \(N\) that traverse exactly \(K\) roads, the sum of the products of the magical values of the roads traversed. It can be efficiently solved using matrix exponentiation of the adjacency matrix.
Analysis
Key Insight: Relationship Between the Adjacency Matrix and Paths
In standard graph theory, it is well known that the \((i, j)\) entry of the \(K\)-th power \(A^K\) of an adjacency matrix \(A\) (where entries are \(1\) if an edge exists and \(0\) otherwise) represents “the number of paths from vertex \(i\) to vertex \(j\) that traverse exactly \(K\) edges.”
In this problem, edges have weights (magical values), and what we want is not the number of paths but “the sum of the products of magical values over all paths.” However, if we set the \((u, v)\) entry of the adjacency matrix to the magical value \(W(u, v)\), then the definition of matrix multiplication:
\[C[i][j] = \sum_{k} A[i][k] \times B[k][j]\]
corresponds exactly to the operation of “summing the products of magical values over all patterns passing through intermediate point \(k\).”
Let’s verify with a concrete example. When \(K = 2\), the \((1, N)\) entry of \(A^2\) is:
\[\sum_{k=1}^{N} W(1, k) \times W(k, N)\]
This is the sum of the products of magical values over all paths of length \(2\) of the form city \(1\) → city \(k\) → city \(N\). Similarly, for \(K\) moves, the \((1, N)\) entry of \(A^K\) gives us the desired answer.
Problem with the Naive Approach
Since \(K\) can be as large as \(10^9\), naively multiplying the matrix \(K\) times would result in \(O(K \times N^3)\), which is far too slow.
Solution: Repeated Squaring of Matrices (Matrix Exponentiation)
We apply the repeated squaring method for integers (the technique of computing \(a^K\) in \(O(\log K)\) multiplications) to matrices. By representing \(K\) in binary and only multiplying the necessary parts, we can reduce the number of matrix multiplications to \(O(\log K)\).
Algorithm
- Construct an \(N \times N\) adjacency matrix \(A\). Set \(A[u][v] = W(u, v)\) (or \(0\) if no road exists).
- Compute \(A^K\) using matrix exponentiation. All operations are performed \(\mod 998244353\).
- The \((0, N-1)\) entry of \(A^K\) (0-indexed, corresponding to city \(1\) to city \(N\)) is the answer.
Procedure for repeated squaring: - Initialize the result matrix \(R\) as the identity matrix. - Examine each bit of \(K\) from the least significant bit; if the bit is set, multiply \(R \leftarrow R \times A^{2^i}\). - At each step, \(A^{2^i}\) is obtained by squaring the value from the previous step.
Complexity
- Time complexity: \(O(N^3 \log K)\)
- A single matrix multiplication is \(O(N^3)\), and matrix exponentiation requires \(O(\log K)\) multiplications.
- With \(N \leq 100\) and \(K \leq 10^9\), this is approximately \(100^3 \times 30 \approx 3 \times 10^7\).
- Space complexity: \(O(N^2)\)
- We only need to store a few matrices.
Implementation Notes
Adding a pruning optimization that skips when
A[i][k] == 0during matrix multiplication can speed things up for sparse graphs.Since magical values \(W_i\) can be up to \(10^9\), take \(\mod 998244353\) at input time.
In Python, matrix exponentiation with \(N = 100\) tends to be slow, but this can be addressed with the above pruning and fast input using
sys.stdin.buffer.read().When no path exists, \(A^K[0][N-1] = 0\) naturally, so no special handling is needed.
Source Code
import sys
def mat_mult(A, B, n, mod):
C = [[0] * n for _ in range(n)]
for i in range(n):
for k in range(n):
if A[i][k] == 0:
continue
aik = A[i][k]
for j in range(n):
C[i][j] = (C[i][j] + aik * B[k][j]) % mod
return C
def mat_pow(M, p, n, mod):
# Initialize result as identity matrix
R = [[0] * n for _ in range(n)]
for i in range(n):
R[i][i] = 1
base = M
while p > 0:
if p & 1:
R = mat_mult(R, base, n, mod)
base = mat_mult(base, base, n, mod)
p >>= 1
return R
def main():
input_data = sys.stdin.buffer.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
M = int(input_data[idx]); idx += 1
K = int(input_data[idx]); idx += 1
MOD = 998244353
# Build adjacency matrix where adj[u][v] = W(u,v)
adj = [[0] * N for _ in range(N)]
for i in range(M):
u = int(input_data[idx]) - 1; idx += 1
v = int(input_data[idx]) - 1; idx += 1
w = int(input_data[idx]) % MOD; idx += 1
adj[u][v] = w
# Matrix exponentiation: adj^K, then answer is result[0][N-1]
result = mat_pow(adj, K, N, MOD)
print(result[0][N - 1] % MOD)
if __name__ == '__main__':
main()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: