GCD
ABC
E
ABC136 E - Max GCD
https://atcoder.jp/contests/abc136/tasks/abc136_e (opens in a new tab)
青色下位。数学。
重要な知見 の gcd は を割り切る とする。このとき、整数 を利用して と表現できるので、 ( は整数)
つまり、今回の問題では元の数列 の操作後の配列 の gcd が解となるが、これは を割り切り、なおかつ が成り立つので、最終的な解 は元の数列 の総和の約数に限られるということである。
本問では計算された各約数 に対して一つずつ操作回数が 以下となるかを判定する。
例えば のとき により、 には か の 2 つの選択肢が存在する。このような形で各 に対して愚直に足すか引くかの 2 通りを試すと計算時間に間に合わないため、まず を で割った余りを考え、その値をソートする。
で余りの値が のとき、これは前の方をマイナス、後ろの方をプラスとすることが最適である(仮にマイナス、プラスとするとき、逆にした場合必ず操作回数が減少するため)。よって前から累積和を計算し、残りの個数 * 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)