1. 程式人生 > >Codeforces-792E Colored Balls(貪心/數學)

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<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;
}