Problem:


D：歪みの国 - Country In Distortion -

物語

アリスはすっかり退屈していました。いつも一緒に遊んでいる白ウサギが、トランプ城へ出かけているからです。（あーあ、こんなことなら一緒に出かければよかったわ。）とアリスは思いました。けれども、ここは歪みの国。そうやすやすと出かけては、ひどく疲れてしまいます。どういうことかというと—

白ウサギは困っていました。トランプ城への道中、ちょっとだけ道を間違えてしまったのです。（困ったなあ。一度戻って、道を良く知っているアリスに案内してもらうことにしよう。）と白ウサギは考えました。それにしても、白ウサギはとっても疲れているみたい。白ウサギは懐中時計を見ながら、

「なんだってこの国の道は、通る度に長さが変わったように感じるんだ！この道、さっきは100メートルくらいに感じたけど、今度は1キロはあるんじゃないか？それも、通り抜けるのにかかる時間はほとんど変わってないって言うのに！」

と叫んでいます。そう、ここは歪みの国。まさに、時々刻々と道が歪み続ける不思議な国なのです。
やっとの思いでアリスの家に着いた白ウサギが開口一番、

「ごめんよアリス。トランプ城まで、道案内をお願いできるかい。」

と言うと、退屈のあまりオフトゥンに突っ伏してしていたアリスは元気に飛び起きました。

「もちろんよ！一緒に行きましょう！」

嬉しい一方で、疲れた様子の白ウサギを見て（でも、あまりに疲れてしまうのは悪いわね。）と思ったアリスは、家の奥から歪みの国の地図を取り出してきました。

「さあ、トランプ城までの疲れない道のりを探すわ！」

問題

　n頂点とm辺からなる無向グラフが与えられる。各辺iの移動にかかる時間はt_iで表される。また、初めの体感移動速度としてv_0が与えられる。その後、辺を1本通る度に体感移動速度が変化する。辺をj本通った後の体感移動速度は、整数a, b, cをパラメータとして以下の式で与えられる。

v_j = (a \times v_{j-1} + b) mod c

辺iを速度v_jで通ると体感移動距離がt_i \times v_jとなる。なお、歪みの国では体感移動速度が0でも移動可能であり、そのときの体感移動距離は0である。

　今、頂点1から出発し頂点nを経由して頂点1に戻ってくるような経路を考える。考えうる経路の中で体感移動距離の総和を最小化せよ。

入力形式

n m
x_1 y_1 t_1
...
x_m y_m t_m
v_0
a b c

入力は全て整数からなる。
1行目には、グラフの頂点数と辺数を表すn,mがこの順で空白区切りで与えられる。
続くm行のうちi行目には、i番目の辺が接続する2頂点x_i,y_iと、通過するのにかかる時間t_iがこの順で空白区切りで与えられる。
m+2行目には、初速度を表すv_0が与えられる。
m+3行目には、速度の計算式のパラメータa,b,cがこの順に空白区切りで与えられる。

制約

各値は整数である。

2 \leq n \leq 500

1 \leq m \leq min\{5000, n(n - 1) / 2\}

各i=1,...,mについて1 \leq x_i < y_i \leq nである。また、1 \leq i < j \leq mを満たすi, jについて、x_i \neq x_jまたはy_i \neq y_jである。つまり自己ループおよび多重辺はない。

各i=1,...,mについて1 \leq t_i \leq 10^8

0 \leq v_0 \leq 49

0 < a < c, 0 \leq b < c, v_0 < c \leq 50

グラフは連結である。すなわち任意の2頂点間に経路があることが保証される。

出力形式

体感移動距離の総和の最小値を1行に出力せよ。

入力例1

4 4
1 2 3
2 3 1
2 4 5
3 4 2
5
4 5 6

出力例1

34

入力例2

6 5
1 2 1
2 3 100
3 4 2
4 5 200
5 6 1
3
4 5 9

出力例2

341

通過するのに時間がかかる辺 (2,3) と (4,5) を通る前に、短い時間で通れる道を往復して、なるべく速度を落とした方が体感移動距離は短い。

入力例3

10 9
1 2 74150933
2 3 13214145
3 4 45636411
4 5 90778512
5 6 85676138
6 7 60913535
7 8 43917556
8 9 47519690
9 10 56593754
33
37 41 47 

出力例3

23049391759

体感移動距離が非常に長くなる場合もある。


Sample input:
4 4
1 2 3
2 3 1
2 4 5
3 4 2
5
4 5 6


Sample output:
34

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline
inf = float('inf')

n,m = map(int,input().split())
pathT = [{} for _ in range(n)]
for i in range(m):
    x,y,t = map(int,input().split())
    x -= 1
    y -= 1
    pathT[x][y] = t
    pathT[y][x] = t

import heapq 
def Dijkstra(edge,start):
    d = [[float('inf'),float('inf')] for _ in range(len(edge))]
    d[start][0] = 0
    pq = [(0,start,0)]
    heapq.heapify(pq)
    while pq:
        dist,p,flag = heapq.heappop(pq)
        toflag = flag or (p%n == n-1)
        if dist > d[p][flag]:continue
        for to,cost in edge[p].items():
            if d[to][toflag] <= dist + cost:continue
            d[to][toflag] = dist + cost
            heapq.heappush(pq, (d[to][toflag], to, toflag))
    return d

v0 = int(input())
a,b,c = map(int,input().split())
V = [v0]
v = v0
Vs = set()
while True:
    v = (a*v + b)%c
    if v in Vs:
        loop = V.index(v)
        break
    # print(v)
    V.append(v)
    Vs.add(v)
p = len(V)

path = [{} for _ in range(p*n)]
for now,nxtD in enumerate(pathT):
    for i,v in enumerate(V):
        for nxt,t in nxtD.items():
            if i+1 != p:
                path[i*n + now][(i+1)*n + nxt] = t*v
            else:
                path[i*n + now][loop*n + nxt] = t*v

d = Dijkstra(path,0)
ans = float('inf')
for i in range(p):
    ans = min(ans, d[i*n][1])
    # d2 = Dijkstra(path,i*n + n-1)
    # # res = float('inf')
    # for j in range(p):
    #     # res = min(res, d2[j*n])
    #     ans = min(ans, d[i*n + n-1] + d2[j*n])
print(ans)

Submission status: Accepted

Solution code:
from heapq import heappush, heappop

def main():
  n, m = map(int, input().split())
  edges = [[] for _ in range(n)]
  for _ in range(m):
    x, y, t = map(int, input().split())
    x -= 1
    y -= 1
    edges[x].append((y, t))
    edges[y].append((x, t))
  
  v0 = int(input())
  a, b, c = map(int, input().split())
  v_next = {}
  v = v0
  while True:
    if v not in v_next:
      v_next[v] = (v * a + b) % c
      v = (v * a + b) % c
    else:break

  dic = {}
  dic[(v0, 0)] = 0
  que = []
  heappush(que, (0, 0, v0))
  while que:
    score, node, v = heappop(que)
    new_v = v_next[v]
    for to, t in edges[node]:
      new_score = score + v * t
      if (new_v, to) not in dic or dic[(new_v, to)] > new_score:
        dic[(new_v, to)] = new_score
        heappush(que, (new_score, to, new_v))
  
  dic2 = {}
  que = []
  for v in range(c):
    if (v, n - 1) in dic:
      dic2[(v, n - 1)] = dic[(v, n - 1)]
      heappush(que, (dic[(v, n - 1)], n - 1, v))
  
  while que:
    score, node, v = heappop(que)
    if node == 0:
      print(score)
      break
    new_v = v_next[v]
    for to, t in edges[node]:
      new_score = score + v * t
      if (new_v, to) not in dic2 or dic2[(new_v, to)] > new_score:
        dic2[(new_v, to)] = new_score
        heappush(que, (new_score, to, new_v))
main()