사람의 세포 수, 약 37조 개. 세포들은 몸 속에서 오늘도 열심히 일하고 있다. 그중에서도 우리의 적혈구는 혈관을 타고 돌아다니며 산소와 영양소를 운반해주는 중요한 역할을 맡고있다.
적혈구는 심장이나 폐 같은 거점들을 돌아다니면서 산소와 영양분을 운반한다. 몸 속에는 총 N개의 거점이 있고, 몇몇 거점은 통로를 통해 서로 이어져 있다. 거점 사이의 통로를 통과하는데는 1초가 걸린다. 하지만 혈관의 곳곳에는 판막이나 공사중인 부분들이 있기 때문에 매 초 거점 사이의 연결관계가 바뀐다. 그럼에도 불구하고 몸의 곳곳이 산소와 영양분을 필요로 하므로 적혈구는 가만히 있을 수 없으며, 매 초 통로를 무조건 하나 타야 한다. 일부 통로는 출발 거점과 도착 거점이 같을 수도 있다. 일부 거점의 특정 순간에는 나가는 통로가 없을 수도 있는데, 이 때는 도착한지 1초 후에 파괴되어 몸과 다시 하나가 된다. 잔혹하지만 우리의 몸은 이렇게 돌아간다.
우리의 적혈구는 매 순간 변하는 몸속 혈관 지도에 길을 헤매지만 그래도 최선을 다해서 하루하루 열심히 일을 하고 있다. 옆에 있던 백혈구가 길을 헤매는 적혈구를 보고 도와주고 싶다는 생각을 했다.
수십 시간의 유주 경험을 통해 백혈구는 몸속 혈관 지도가 T 초를 주기로 반복된다는 것을 알게 되었다. 이 사실을 정리해서 적혈구가 거점 A에서 출발하여 정확히 D초 후 거점 B에 도달하게 되는 경우의 수를 모든 거점의 순서쌍에 대해 구해주고자 하지만 너무나도 단세포이기 때문에 머리가 나빠서 계산을 하지 못했다. 한 경로는, D초 동안 통과한 통로의 순열로 정의된다. 백혈구를 도와서 적혈구가 D초 동안 한 거점에서 다른 거점까지 움직일 수 있는 경우의 수를 구해주자!
이러한 행렬의 거듭제곱을 다룬 문제가 더 있었는데 지금은 기억이 잘 나지 않는다.. 핵심은 이런 식으로, 행렬의 거듭제곱을 구하여 풀이하는 것이다. D//T만큼 T주기 행렬을 거듭제곱하고, 그 나머지 행렬을 곱셈하면 정답을 얻을 수 있다.
풀이 코드
import sys
input = sys.stdin.readline
MOD = 1000000007
T, N, D = map(int, input().split())
mat_list = list()
def matmul(a, b) :
c = [[0]*N for _ in range(N)]
for i in range(N) :
for j in range(N) :
for k in range(N) :
c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % MOD
return c
def matpow(a, p) :
if p == 1 :
return a
b = matpow(a, p//2)
b = matmul(b, b)
if p % 2 == 0 :
return b
return matmul(b, a)
for _ in range(T) :
mat = [[0]*N for _ in range(N)]
t = int(input())
for _ in range(t) :
a, b, c = map(int, input().split())
mat[a-1][b-1] = c
if not mat_list :
mat_list.append(mat)
else :
mat_list.append(matmul(mat_list[-1], mat))
m, r = D // T, D % T
ans = [[0]*N for _ in range(N)]
if m > 0 :
ans = matpow(mat_list[-1], m)
if r > 0 :
ans = matmul(ans, mat_list[r-1])
elif r > 0 :
ans = mat_list[r-1]
for _ans in ans :
print(*_ans)