問題概要
リンク
長さN N N の整数列A 1 , A 2 , ⋯ A N A_1,A_2,\cdots A_N A 1 , A 2 , ⋯ A N とK K K が与えられる。
以下の操作をK K K 回まで行い、整数列を加工できる。
1 ≤ i , j ≤ N 1 \leq i,j \leq N 1 ≤ i , j ≤ N を満たすi , j i,j i , j を選び、A i A_i A i に 1 を足し、A j A_j A j から 1 を引く。
この操作によって整数列を加工後、A 1 , . . . , A N A_1,...,A_N A 1 , ... , A N の共通の約数で最大のものを求めよ。
制約
2 ≤ N ≤ 500 2 \leq N \leq 500 2 ≤ N ≤ 500
1 ≤ A i ≤ 1 0 6 1 \leq A_i \leq 10^{6} 1 ≤ A i ≤ 1 0 6
0 ≤ K ≤ 1 0 9 0 \leq K \leq 10^{9} 0 ≤ K ≤ 1 0 9
解法
この問題のポイントは以下の 2 つ。
どのような性質を満たす数が解の候補となるか
解の候補となった数が条件を満たすことをどのように判定するか
どのような性質を満たす数が解の候補となるか
加工後の整数列をA 1 ′ , A 2 ′ , ⋯ A N ′ A'_1,A'_2,\cdots A'_N A 1 ′ , A 2 ′ , ⋯ A N ′ とし、性質を見てみる。
整数列A 1 , A 2 , ⋯ A N A_1,A_2,\cdots A_N A 1 , A 2 , ⋯ A N に対して行える操作は、どこかを 1 増やし、どこかを 1 減らすことなので、数列全体の値の合計は変化しない。よって∑ i = 1 N A i = ∑ i = 1 N A i ′ \sum_{i=1}^{N} A_i = \sum_{i=1}^{N} A'_i ∑ i = 1 N A i = ∑ i = 1 N A i ′ が成り立つ。
また、全てのA i ′ A'_i A i ′ はこの問題の解となるある数x x x の倍数になっているので、適当な数をa a a とすると∑ i = 1 N A i ′ = a × x \sum_{i=1}^{N} A'_i = a \times x ∑ i = 1 N A i ′ = a × x と表すことができる。よって、∑ i = 1 N A i = ∑ i = 1 N A i ′ = a × x \sum_{i=1}^{N} A_i = \sum_{i=1}^{N} A'_i = a \times x ∑ i = 1 N A i = ∑ i = 1 N A i ′ = a × x となる。
このことから、求めたい数x x x は、A 1 , . . . , A N A_1,...,A_N A 1 , ... , A N の総和∑ i = 1 N A i \sum_{i=1}^{N} A_i ∑ i = 1 N A i の約数の中にあることが分かった。
自然数n n n の約数は、下記のような方法でO ( n ) O(\sqrt n) O ( n ) で列挙することができる。
fn enumerate_divisor ( n: usize ) -> Vec < usize > {
let mut i = 1 ;
let mut divisors = vec! [ ] ;
while i * i <= n {
if n % i == 0 {
divisors. push ( i) ;
divisors. push ( n / i) ;
}
i += 1 ;
}
divisors
}
条件を満たすことをどのように判定するか
解の候補x x x を用意した時、全てのA i ′ A'_i A i ′ をx x x の倍数にするために何回操作が必要なのかを考える。これが分かれば、解の候補を大きい順に見ていき、K K K 回以下の操作で作ることができることが判明したらその時のx x x が求める答えとなる。
まずは問題で定義されている操作を無視し、A i A_i A i に何かを足したり引いたりして最小の増減でx x x の倍数に変形するためにはどうすればいいか考える。これは、A i + d A_i + d A i + d をx x x で割った時の余りが 0 になるようにうまく値を調整することで下記の 2 通りのどちらかで実現できる。
A i A_i A i から何かを引いてx x x の倍数にする場合は、A i m o d x A_i {\rm mod} x A i mod x の値をA i A_i A i から引く。 (以後 マイナス 型と呼ぶ)
逆にA i A_i A i に何かを足してx x x の倍数にする場合は、x − A i m o d x x - A_i {\rm mod} x x − A i mod x をA i A_i A i に足す。 (以後 プラス 型と呼ぶ)
このようにx x x の倍数にするために必要な最小の増減量は分かったが、問題で定義されている操作と等価にするには、全てのA i A_i A i に対する増減の総和が 0 になっている必要がある。次はどうやってこの帳尻を合わせるのかを考える。
d i d_i d i をA i + d i = A i ′ A_i + d_i = A'_i A i + d i = A i ′ となる数とした時、∑ i = 1 N d i = 0 \sum_{i=1}^{N} d_i = 0 ∑ i = 1 N d i = 0 となる。
マイナス 型であればd i = − A i m o d x d_i = - A_i {\rm mod} x d i = − A i mod x 、プラス 型であればd i = x − A i m o d x d_i = x - A_i {\rm mod} x d i = x − A i mod x である。マイナス 型と プラス 型の違いはx x x の部分のみなので、∑ i = 1 N d i \sum_{i=1}^{N} d_i ∑ i = 1 N d i は、プラス 型を選択した回数をa a a として
∑ i = 1 N d i = a × x − ∑ i = 1 N A i m o d x \sum_{i=1}^{N} d_i = a \times x - \sum_{i=1}^{N} A_i {\rm mod} x ∑ i = 1 N d i = a × x − ∑ i = 1 N A i mod x
と表されることが分かる。x x x が∑ i = 1 N A i \sum_{i=1}^{N} A_i ∑ i = 1 N A i の約数という前提で考えると、0 ≤ b ≤ N 0 \leq b \leq N 0 ≤ b ≤ N となるあるb b b に対して
∑ i = 1 N A i m o d x = b × x \sum_{i=1}^{N} A_i {\rm mod} x = b \times x ∑ i = 1 N A i mod x = b × x
が成り立つ。このb b b は∑ i = 1 N A i m o d x \sum_{i=1}^{N} A_i {\rm mod} x ∑ i = 1 N A i mod x をx x x で割ることで求めることができる。
∑ i = 1 N d i = a × x − b × x \sum_{i=1}^{N} d_i = a \times x - b \times x ∑ i = 1 N d i = a × x − b × x となるため、a = b a = b a = b とすればよい。これでプラス型を選択する回数a a a を特定できた。
あとはどのi i i で合計a a a 回のプラス型を選択するかだが、これは単にx − A i m o d x x - A_i {\rm mod} x x − A i mod x が小さいもの、つまりA i m o d x A_i {\rm mod} x A i mod x が大きい順にi i i を並べた時の最初のa a a 個とすればよい。
プラス型かマイナス型のd i d_i d i を記録しておくことで、「1 ≤ i , j ≤ N 1 \leq i,j \leq N 1 ≤ i , j ≤ N を満たすi , j i,j i , j を選び、A i A_i A i に 1 を足し、A j A_j A j から 1 を引く」操作の回数も分かるので、K K K 回以下の操作で全てのA i ′ A'_i A i ′ をx x x の倍数にできるかを判定できる。
まとめ
∑ i = 1 N A i \sum_{i=1}^{N} A_i ∑ i = 1 N A i の約数が解の候補となる。解の候補である各x x x に対し、K K K 回の操作で各A i ′ m o d x = 0 A'_i mod x = 0 A i ′ m o d x = 0 が構成できるかを調べる。調べる方法は下記の通り。
a = ( ∑ i = 1 N A i m o d x ) / x a = (\sum_{i=1}^{N} A_i {\rm mod} x) / x a = ( ∑ i = 1 N A i mod x ) / x を計算し、必要なプラス 型の回数を調べる。
A i m o d x A_i {\rm mod} x A i mod x が大きい順にi i i を並べ、その順にa a a 個のx − A i m o d x x -A_i {\rm mod} x x − A i mod x を足し合わせたものが必要な操作の回数になる。
必要な操作の数がK K K 回以下の最大のx x x が解となる。