There are n boxes with colored balls on the table. Colors are numbered from 1 to n. i-th box contains ai balls, all of which have color i. You have to write a program that will divide all balls into sets such that:
- each ball belongs to exactly one of the sets,
- there are no empty sets,
- there is no set containing two (or more) balls of different colors (each set contains only balls of one color),
- there are no two sets such that the difference between their sizes is greater than 1.
Print the minimum possible number of sets.
The first line contains one integer number n (1 ≤ n ≤ 500).
The second line contains n integer numbers a1, a2, ... , an (1 ≤ ai ≤ 109).
Print one integer number — the minimum possible number of sets.
3 4 7 8
5
2 2 7
4
题解:设最少的球是有a[1]个,那么所有set的容量一定不会超过a[1]+1(任意两个set之间容量差不能超过1),只要枚举1~a[1]+1即可,只不过a[1]<=1e9,因此正常的暴力枚举是没办法过的。设s=sqrt(a[1]),那么要枚举[1,s]是很容易的,但是要枚举[s,s^2]就需要转化一下:
设k∈[s,s^2]为每个set的容量,那么x=a[1]/k就表示第一个球需要用x个set装,可以想到x∈[1,s],于是我们只要再枚举x就等于枚举完k。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MX = 505;
int n, a[MX];
bool Check1(int x, LL& cnt)
{
if (x <= 0) return false;
cnt = 0;
for (int i = 1; i <= n; i++) {
if (a[i] % x <= a[i] / x) { //每个set装x个球,剩余的球不能超过set的个数
cnt = cnt + (LL)ceil(a[i] * 1.0 / (x + 1));
}
else return false;
}
return true;
}
int main()
{
//freopen("in.txt", "r", stdin);
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
LL cnt = 0, ans = 1LL << 60;
int sq = (int)sqrt(a[1]) + 1;
//相当于枚举第一个球由sqrt(a[1])~a[1]个set装
for (int i = 1; i <= sq; i++) {
int now = a[1] / i;
if (Check1(now, cnt)) ans = min(ans, cnt);
if (a[1] % i == 0) if (Check1(now - 1, cnt)) ans = min(ans, cnt);
if (ans != 1LL << 60) break;
}
//相当于枚举每个set装1~sqrt(a[1])个球
for (int i = sq + 1; i >= 1; i--) {
if (Check1(i, cnt)) ans = min(ans, cnt);
if (ans != 1LL << 60) break;
}
printf("%I64d\n", ans);
}
return 0;
}