Official

K - Gcd of Sum Editorial by kaage


累積和を取った数列 \(S\) を考えます。つまり、

\[S_i = \sum_{j=1}^i A_j\]

とします。このとき、約数が \(D\) となるような \(K\) 個への切り分け方が存在する必要十分条件は、\(S_N\equiv 0 \pmod D\) かつ \(S_i\equiv 0 \pmod D\) となる \(1\leq i\leq N\)\(K\) 個以上存在することです。 これを使うと、\(D\) について \(O(N)\) で切り分け方が存在する最小の \(K\) を見つけることができるので、ありうる \(D\) を全探索すればよいです。

\(S_N\) の最大値は高々 \(9\cdot 10^4\) 程度なので \(S_N\) 以下の \(D\) を全探索しても C++ などの高速な言語なら間に合いますし、\(S_N\equiv 0\pmod D\) を使えばもっと計算量を落とすことができます。(\(O(N\sqrt{sum(A)})\) 程度)

#include <iostream>
#define rep(i, n) for (int i = 0; i < int(n); i++)
#define REP(i, n) for (int i = 1; i <= int(n); i++)
int N, A[310], ans[310];
int main() {
	std::cin >> N;
	rep(i, N) {
		std::cin >> A[i];
		if (i) A[i] += A[i - 1];
	}
	REP(i, 90000) {
		if (A[N - 1] % i) continue;
		int cnt = 0;
		rep(j, N) {
			if (A[j] % i == 0) cnt++;
		}
		REP(j, cnt) ans[j] = i;
	}
	REP(i, N) std::cout << ans[i] << std::endl;
	return 0;
}

posted:
last update: