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
Note

In the first example the balls can be divided into sets like that: one set with 4 balls of the first color, two sets with 3 and 4 balls, respectively, of the second color, and two sets with 4 balls of the third color.



讲道理这道题现在还是不知道正解是啥。。。

看到了一份能看懂的代码,先贴上来。再说我自己的想法。


#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;

const int MAXN = 500 +10;
const long long INF=0x7fffffffffffffff;
long long ans=INF;
long long a[MAXN];
int n;

void solve(long long x){
    long long s=0;
    if(x==0)
        return;
    for(int i=0;i<n;i++){
        long long p=a[i]/x;
        long long q=a[i]%x;
        if(p==0)
            return;
        if(p>=q){
            s+=(a[i]+x)/(x+1);
        }else
            return;
    }
    ans=min(ans,s);
}



int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%I64d",a+i);
    }
    sort(a,a+n);
    for(int i=1;i*i<=a[0];i++){
        solve(a[0]/i);
        solve(a[0]/i+1);
        solve(i);
        solve(a[0]/i-1);
    }
    printf("%I64d\n",ans);
}



其实就是暴力,因为每一份的个数肯定不能超过最小的数,所以针对最小的数枚举一下。不过在这个代码里面那个a[i]+x/(x+1)不太懂

我是用不定方程做的。

对于ax+by=n,x=x'-bt,y=y'+at.x',y'为一组特解。

对于p=a[I]/x,q=a[I]%x.

只要p>=q,就能把q分成q个1加到其他集合里面。(p-q)*x+q*(x+1)=a[i],总个数就是p+t,求出t的范围即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;

const int MAXN = 500 +10;
const long long INF=0x7fffffffffffffff;
long long ans=INF;
long long a[MAXN];
int n;

void solve(long long x){
    long long s=0;
    if(x==0)
        return;
    for(int i=0;i<n;i++){
        long long p=a[i]/x;
        long long q=a[i]%x;
        if(p<q){
            return;
        }
        long long X=(a[i]-q)/x;
        long long Y=(p-q)/(x+1);
        long long temp=min(X,Y);
        s+=p-temp;
    }
    ans=min(ans,s);
}


int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%I64d",a+i);
    }
    sort(a,a+n);
    for(int i=1;i*i<=a[0];i++){
        solve(a[0]/i);
        solve(a[0]/i+1);
        solve(i);
        solve(a[0]/i-1);
    }
    printf("%I64d\n",ans);
}

然而居然被卡常乐。。

气哭



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值