AtCoder Beginner Contest 167 D問題
D問題
難易度:茶色
茶色の中でも難し目の問題を解いてみましたが、
TLEとWAのダブルパンチを喰らい、結局以下のサイトを参考にする形となりました。
K(≤10**5)個の街に設置されているワープマシンを
N(≤10**18)回使用したらどこの街に飛ばされるかという問題です。
Nに関しては(≤10**18)なのでまともに解いていてはTLEです。
Kに関しては(≤10**5)なのでO(N)回の計算量程度は実行可能です。
まず考えるべきなのは、「ループ」です。
途中から同じ街を何度もループし始めます。
この規則性を見破り、ループ+剰余の式を作成し、結果的にK回目のループ先を導きます。
規則性の見つけ方:TLE
正直考え方は良い線でしたが、規則性・ループをまとめ方にTLEを出してしまいました。
itertoolsのCountersを使用したりしても単体の計算量がO(N)の場合、
for文内に埋め込んでしまうと、全体でO(N**2)となってしまいますねえ・・・。
- 訪れた回数配列:visit
- 訪れた街を列挙した配列:goal
- 2回目訪れた街を列挙(ループしてる):loop
Countersを使用しなくとも、
配列のindexをkey-1、要素をvaluesに対応づけているので、
全体でO(N)で動作します。
特異なケース:WA
剰余 = 序盤の規則性がないゾーン = len(goal) - len(loop)
あとこいつを考慮してませんでした。
WAの原因はこいつです。
K と 剰余の差分から、規則性のある数列に置き換えます。
それにはK > 剰余が前提です。
以下の場合分けを考えないといけませんでしたね。
- goalがKより大きいケース
- goalがKより小さいケース
与えられた
from collections import Counter N, K = map(int,input().split()) tele = list(map(int, input().split())) #A1から順にワープした時の経由順 now = 0 goal,loop,visit = [],[],[0]*N while visit[now]!=2: if visit[now]==0: goal.append(now) else: loop.append(now) visit[now] += 1 now = tele[now]-1 if len(goal)>K: print(goal[K]+1) else: amari = len(goal)-len(loop) print(loop[(K-amari)%len(loop)]+1)