【CF792E】Colored Balls(数论分块)

题目链接

大意

\(N\)种颜色的球,第\(i\)种球有\(Ai\)个,要求把球分成几个集合,使得:

  1. 一个集合里的球只能有一种颜色。
  2. 任意两个集合的球的数量相差不能超过1。

求这些球至少需要分几个集合。

思路

我们设这些集合的大小为\(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\)的取值为多少:

  • 由于\(Ai=X\cdot Ans+ Y\)\(Ans=\left \lfloor \frac{Ai-Y}{X} \right\rfloor\),在这种情况下,我们只知道\(X\)\(Ai\),所以考虑\(Y\)的取值情况。
    由于\(0\le Y\le X\),则有\(\frac{Ai-X}{X}\le \frac{Ai-Y}{X}\le \frac{Ai}{X}\)\(\left \lfloor \frac{Ai-X}{X}\right \rfloor\le \left \lfloor \frac{Ai-Y}{X}\right \rfloor\le \left \lfloor \frac{Ai}{X}\right \rfloor\)
    \(\left \lfloor \frac{Ai}{X}-1\right \rfloor\le Ans\le \left \lfloor \frac{Ai}{X}\right\rfloor\)\(\left \lfloor \frac{Ai}{X}\right \rfloor-1\le Ans\le \left \lfloor \frac{Ai}{X}\right\rfloor\)
    \(Ans=\left \lfloor \frac{Ai}{X}\right \rfloor-1\)\(\left \lfloor \frac{Ai}{X}\right\rfloor\)
  • 另:当\(Ans=\left \lfloor \frac{Ai}{X}\right \rfloor-1\)时,\(Ai=X\cdot Ans+Y=X\cdot\left \lfloor \frac{Ai}{X}\right\rfloor+Y-X\)
    又由于\(Y-X\le 0,X\cdot\left \lfloor \frac{Ai}{X}\right\rfloor\le Ai\),所以\(Ans=\left \lfloor \frac{Ai}{X}\right \rfloor-1\)时,只在\(Ai\%X=0\)时成立。
    (注:也可以这样理解:\(Ai=X\cdot Ans=X\cdot(Ans-1)+X\)

综上,\(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
*/
posted @ 2019-11-14 11:26  孤攀客  阅读(354)  评论(0编辑  收藏  举报