有\(N\)种颜色的球,第\(i\)种球有\(Ai\)个,要求把球分成几个集合,使得:
求这些球至少需要分几个集合。
我们设这些集合的大小为\(Ans\)与\(Ans+1\),考虑如何判断一个\(Ans\)是否可行。
由于一个集合里只能有一种颜色,所以我们可以对于每一种颜色都单独考虑。
设当前颜色为\(i\),我们设 \(Ai=X\cdot Ans+ Y\),其中\(Ans,Y\)满足\(Ans>Y\)。
那么易发现,若\(Y>X\),则剩下的\(Y\)个数就算平均分到\(X\)个集合里,也会剩下\((Y-X)\)个数,那么我们的\(Ans\)就不符合条件了。
又由于在\(Ai=X\cdot Ans+ Y\)式子中的\(X=\left \lfloor Ai/Ans \right \rfloor,Y=Ai\%Ans\)
化简一下,一个\(Ans\)可行的条件为:对于任意\(i\),都满足\(\left \lfloor Ai/Ans \right \rfloor\ge Ai\%Ans\)
尽管已经知道了如何判断一个\(Ans\)是否可行,但如果我们暴力去枚举\(Ans\),复杂度也是\(O(N\times A)\),考虑优化。
首先有一个很明显的性质就是\(Ans\le Min(Ai)\),即\(Ans\)至多是\(A\)中的最小值。
对于\(Ans\)的判断式:\(\left \lfloor Ai/Ans \right \rfloor\ge Ai\%Ans\)。
发现在\(Ans\le\sqrt{Ai}\)时,肯定是恒满足的,因为
\(\left \lfloor Ai/Ans \right \rfloor\ge \sqrt{Ai}\ge Ans\ge Ai\%Ans\)
所以所有满足\(Ans\le\sqrt{Ai}\)的\(Ans\)肯定都是可行的\(Ans\)。
考虑\(Ans>\sqrt{Ai}\)的情况:
在这种情况下,我们的判断式就会满足\(\left \lfloor Ai/Ans \right \rfloor<\sqrt{Ai}<Ans\),
所以我们不妨枚举\(\left \lfloor Ai/Ans \right \rfloor\)即\(X\)的取值,这样的复杂度是\(O(N\cdot\sqrt{A})\),可以接受。
然后又由于要让\(Ans\)可行,所以我们要让\(\left \lfloor Ai/Ans \right \rfloor\ge Ai\%Ans\),即\(Ans>X\ge Y\).
考虑满足上述条件下的\(Ans\)的取值为多少:
综上,\(Ans=\left \lfloor \frac{Ai}{X} \right \rfloor\),特殊的,当\(Ai\%X=0\)时,\(Ans\)还有可能为\((\left \lfloor \frac{Ai}{X}\right\rfloor-1)\)。
在求出\(Ans\)(集合大小中较小值)后,统计答案时就优先放\(Ans+1\),再放\(Ans\)这样的考虑就行了。
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int MAXN=505;
int N,A[MAXN];
int St,Mi=1e9,Ans;
int Check(int ans){
for(int i=1;i<=N;i++)
if(A[i]/ans<A[i]%ans)
return 0;
return 1;
}
long long Get(){
long long ans=0;
for(int i=1;i<=N;i++){
int m=(Ans+1-A[i]%(Ans+1))%(Ans+1);//还剩m个空位需要Ans来补.
ans+=m+(A[i]-m*Ans)/(Ans+1);
}
return ans;
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%d",&A[i]),Mi=min(Mi,A[i]);
St=sqrt(Mi)+1;Ans=St-1;
for(int i=1;i<=St;i++){
if(Check(Mi/i)){
Ans=max(Ans,Mi/i);
break;
}
if(Mi%i==0)
if(Check(Mi/i-1)){
Ans=max(Ans,Mi/i-1);
break;
}
}
printf("%lld\n",Get());
}
/*
A<=(A/K)*(K+1)
ceil(A/val)-1<=K
*/
原文:https://www.cnblogs.com/ftotl/p/11855858.html