Codeforces-792E Colored Balls(贪心/数学)

E. Colored Balls
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

There are n boxes with colored balls on the table. Colors are numbered from 1 to ni-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.

Input

The first line contains one integer number n (1 ≤ n ≤ 500).

The second line contains n integer numbers a1, a2, ... , an (1 ≤ ai ≤ 109).

Output

Print one integer number — the minimum possible number of sets.

Examples
input
3
4 7 8
output
5
input
2
2 7
output
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
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;
}


你可能感兴趣的:(贪心)