题目链接:http://codeforces.com/problemset/problem/792/E
题意:
有n种颜色的球,第i种球有ai个,让你把球分成几个集合。
要求:
1、一个集合里的球只能有一种颜色。
2、每两个集合的球的数量相差不能>1;
让你求出这些球最少分几个集合。
1<=ai<=1e9,1<=n<=500;
分析:
枚举找出最小的单位x,让每个颜色的球都能分成若干堆数量为x或者x-1的,就达到了要求。
所以对于x,有要求对于所有的i,如果ai%x==0,满足要求。否则就要使ai%x+ai/x>=x-1;
意思是:
如果ai/x=b,ai%x=d,并且d!=0;
说明ai可以被分成b+1堆,前b堆是每堆有x个,最后一堆是d个。
c+d=x-1;
如果有c堆每堆是x的,让这c堆每堆拿出 1放在最后一堆上,最后一堆就是x-1,而那c堆也是x-1,其他堆是x,这样就满足要求了。
所以如果c>=b的话,就是说d+b>=x-1的话,x对ai就满足要求了。而如果x对所有的ai都满足要求,就可以了。
x越大,分出的堆就越少,所以这个最小的x就从最小的ai开始枚举,把边界都枚举一遍。然后ai/2,ai/3,ai/4….总之一定是可以的。找到了就break;
具体看代码;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int INF=0x3f3f3f3f*2;
int a[505];
int n;
ll work(int x)
{
ll sum=0;
for(int i=0;i<n;i++)
{
if(a[i]%x==0||(a[i]/x+a[i]%x>=x-1))
sum+=a[i]/x+(a[i]%x!=0);
else
return 0;
}
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
ll s;
for(int k=1;k<=a[0];k++)
{
s=work(a[0]/k+1);
if(s)
break;
s=work(a[0]/k);
if(s)
break;
s=work(a[0]/k-1);
if(s)
break;
}
printf("%lld\n",s);
}//其实我以为会超时,,还在想是不是有什么特殊的优化方法,然后就过了,很惊讶。