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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值