Google Code Jam 2019 Round2 : Contransmutation

問題. Contransmutation

 N 種類の金属があり,1番目の金属は鉛である. i 番目の金属を1グラム使用して, R_{i_1} 番目と  R_{i_2} 番目の金属をそれぞれ1グラム生成できる.最初に  i 番目の金属は  g_i グラムある.金属の生成方法を繰返し行い鉛のグラム数を最大化せよ.そして,そのときの鉛の最大グラム数の  10^9 + 7 による剰余を答えよ.ただし,鉛を無限に生成できるときは "UNBOUNDED" と答えよ.

制約 2 \le N \le 10^5,  0 \le g_i \le 10^9

解法.強連結成分分解

 i 番目の金属を頂点  v_i として,弧を  (v_i, v_{R_{i_1}}), (v_i, v_{R_{i_2}}) を加えた有向グラフ  G を考える. G を強連結成分分解して,その強連結成分全体を  (C_1, C_2, \ldots, C_k) とする.ただし,添字の昇順にトポロジカルソートされているとする.各強連結成分  C_i 内で生成を行うと, |C_i| が1でない限り  C_i 内の総グラム数が減ることはない.また, C_i 内に含まれる弧数の方が  |C_i| よりも真に大きい場合は  C_i 内の総グラム数は真に増加することが分かる.したがって, C_i 内に最初のグラム数が正の頂点が存在するか, j < i C_j から  C_i への道が存在して  C_j 内に最初のグラム数が正の頂点が存在する場合に,  C_i 内のすべての頂点は無限に生成することができる.
各頂点の出次数はちょうど 2 なので,弧数は頂点数のちょうど 2 倍となる.したがって,強連結成分分解は  O(N) 時間で求まるので,頂点  v_1 が無限に生成可能かどうかは  O(N) 時間で判定できる.

次に, v_1 が無限に生成できない場合に最大で何グラム得ることができるかを考える. v_1 を含む強連結成分を  C_i とする.このとき,強連結成分  C_j \, (j \le i) 内の頂点  v_{j_1} を分解して  v_1 のグラム数を増やすことを考える. (C_1, C_2, \ldots, C_k) の成分グラフを  G' とする.ただし, G' は多重辺を含むとする.このとき, C_j から  C_i への  G' 上の異なる道の数を  p とすると, v_1 v_{j_1} によって  p \times g_{j_1} グラムだけ増加する.

計算時間 O(N)

成分グラフの多重辺を考えないでハマった.道の数の剰余をとらないでハマった.
成分グラフを陽に構成するよりも,トポロジカルソートの降順に行うと簡潔に実装できた.
大まかな解法はすぐ浮かんだので他の問題よりも取り掛かりやすかったかも.