問題概要
色のボールがあり、 番目の色で塗られたボールは 個ある。
これらのボールを以下の条件を全て満たすように箱に入れる。
- それぞれの箱について、箱の中にあるボールの色は 種類のみ
- 空箱が存在しない
- 箱に入っているボールの個数の最大値と最小値の差は高々
必要な箱の個数の最小値を求めよ。
解説
色目のボールを箱に入れることを考える。積を考えると、「箱の個数」または「箱に入れるボールの個数」のいずれかは 以下であることが分かる。なのでそれぞれについて問題を解けばよい。
箱の個数が定まっているときに、それぞれの箱に入れるボールの個数がどうなるべきかは割り算をするとわかる。(剰余が のときに注意)
あとは「箱に入れるボールの個数が 個または であるときに、条件を満たす入れ方が可能か?また可能な時の箱の数の最小値がいくらか?」を解ければ良いことになる。
実は、各 について最適な箱の数は であり、入れ方が可能かどうかの判定は を満たすかどうかで可能である。
上の条件を満たすと仮定すると が成立するが、これは「全ての箱に 個入れたと仮定した時の個数」と「全ての箱に 個入れたと仮定した時の個数」で を挟んでいることに相当している。
ソースコード
int main() { int N; scanf("%d", &N); vector<int> A(N); for(int i=0; i<N; i++) scanf("%d", &A[i]); ll ans = INF; { // 箱の個数について for(int x=1; x*x<=A[0]; x++) { int d = A[0] / x, m = A[0] % x; for(int k=d; k>=d-(m==0); k--) { int mi = k, ma = k+1; ll sum = 0; for(int i=0; i<N; i++) { ll b = (A[i] + ma - 1) / ma; if(mi * b <= A[i]) sum += b; else sum = INF; } ans = min(ans, sum); } } } { // 箱に入れるボールの個数について (x か x+1) for(int x=1; x*x<=A[0]; x++) { int mi = x, ma = x+1; ll sum = 0; for(int i=0; i<N; i++) { ll b = (A[i] + ma - 1) / ma; if(mi * b <= A[i]) sum += b; else sum = INF; } ans = min(ans, sum); } } cout << ans << endl; return 0; }
で分けて何かするのは思い浮かんでいたけど、判定の式がわからなかった。