🚧 This website is under construction. 🚧
AtCoder
ABC
136
E

GCD
ABC
E

ABC136 E - Max GCD

https://atcoder.jp/contests/abc136/tasks/abc136_e (opens in a new tab)
青色下位。数学。

重要な知見 A1,A2,,AnA_1,A_2,\ldots,A_n の gcd は A1+A2++AnA_1+A_2+\dots+A_n を割り切る gcd(A1,A2,,An)=g\gcd{(A_1,A_2,\ldots,A_n)}=g とする。このとき、整数 aia_i を利用して A1=a1g,A2=a2g,,An=angA_1=a_1g,A_2=a_2g,\ldots,A_n=a_ng と表現できるので、 gcd(A1+A2+An)=gcd((a1+a2++an)g)=kg\gcd{(A_1+A_2\dots+A_n)}=\gcd{((a_1+a_2+\dots+a_n)g)}=kg ( kk は整数)

つまり、今回の問題では元の数列 AiA_i の操作後の配列 A1,A2,,AnA_1',A_2',\ldots,A_n' の gcd gg が解となるが、これは A1+A2++AnA_1'+A_2'+\dots+A_n' を割り切り、なおかつ A1+A2++An=A1+A2++ANA_1'+A_2'+\dots+A_n'=A_1+A_2+\ldots+A_N が成り立つので、最終的な解 gg は元の数列 AiA_i の総和の約数に限られるということである。

本問では計算された各約数 gig_i に対して一つずつ操作回数が kk 以下となるかを判定する。

例えば g=7,Ak=20g=7,A_k=20 のとき Ak%g=6A_k\%g=6 により、 AkA_k には +1+16-6 の 2 つの選択肢が存在する。このような形で各 AiA_i に対して愚直に足すか引くかの 2 通りを試すと計算時間に間に合わないため、まず AiA_igg で割った余りを考え、その値をソートする。

g=7g=7 で余りの値が {1,1,2,3,3,4}\{1,1,2,3,3,4\} のとき、これは前の方をマイナス、後ろの方をプラスとすることが最適である(仮にマイナス、プラスとするとき、逆にした場合必ず操作回数が減少するため)。よって前から累積和を計算し、残りの個数 * g - 残りの和と一致したものが操作回数の最小値となる。

import itertools
 
n, k = map(int, input().split())
a = list(map(int, input().split()))
 
sum_a = sum(a)
divs = set()
for d in range(1, int(sum_a**.5) + 2):
    if sum_a % d == 0:
        divs.add(d)
        divs.add(sum_a // d)
 
ans = 1
for x in divs:
    mods = sorted(e % x for e in a)
    acc = list(itertools.accumulate(mods, initial=0))
    for i in range(1, n):
        if acc[i] == (n - i) * x - (acc[n] - acc[i]) and acc[i] <= k:
            ans = max(ans, x)
 
print(ans)