AT274の技術だったりなかったり

あっとのTECH LOG

競プロのこととか技術のこととか。たまに日常を書きます。

Judge System Update Test Contest 202004 D - Calculating GCD

問題原文

atcoder.jp

問題要旨

長さ  N の正整数列  A_1, A_2... A_N がある。また、  Q 個の1より大きい整数  S_1, S_2, ... S_Q が与えられる。
 X = S_i にした場合の以下の問題の答えを求めよ。

  • 始め整数  X がある。 j = 1, 2, ... N の順番に、  X gcd(X, A_j) で置き換える。
    途中で  X = 1 となる場合はそうなる最小の  j を、ならない場合は最終的な  X の値を求めよ。

  •   1 \leq N \leq 10^{5}

  •   1 \leq A_i \leq 10^{9}
  •   1 \leq S_i \leq 10^{9}

解法

最後にようやく1になる & 毎回  X が変化すると仮定してみる。
すると「最大で何回  X が変化するか」は 2 × 2 × 2 × をしていって  A_i の制約を超えないギリギリで、これはたったの29回とかになる。
よって   A の累積GCDを追っていって、変化する場所を記録すると、そのような  j についてのみチェックをすることで、愚直に解ける。
ランレングス圧縮っていうらしい!

実装

ありがとう fractions.gcd、こんにちは math.gcd

from math import gcd

N, Q = map(int, input().split())
A = list(map(int, input().split()))
S = list(map(int, input().split()))

changed_index = [0]
GCD = A[0]
for i, a in enumerate(A[1:], start=1):
    nextGCD = gcd(GCD, a)
    if GCD != nextGCD:
        changed_index.append(i)
    GCD = nextGCD

for s in S:
    X = s
    for ci in changed_index:
        X = gcd(X, A[ci])
        if X == 1:
            print(ci + 1)
            break
    else:
        print(X)

感想

実は制約を良くみると、考えるべきものがぐっと少なくなるパターン、かな?