【CF792E】Colored Balls(数论分块)

题目链接

大意

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

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

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

思路

我们设这些集合的大小为(Ans)(Ans+1),考虑如何判断一个(Ans)是否可行。
由于一个集合里只能有一种颜色,所以我们可以对于每一种颜色都单独考虑。

设当前颜色为(i),我们设 (Ai=Xcdot Ans+ Y),其中(Ans,Y)满足(Ans>Y)
那么易发现,若(Y>X),则剩下的(Y)个数就算平均分到(X)个集合里,也会剩下((Y-X))个数,那么我们的(Ans)就不符合条件了。

又由于在(Ai=Xcdot Ans+ Y)式子中的(X=left lfloor Ai/Ans ight floor,Y=Ai\%Ans)
化简一下,一个(Ans)可行的条件为:对于任意(i),都满足(left lfloor Ai/Ans ight floorge Ai\%Ans)


尽管已经知道了如何判断一个(Ans)是否可行,但如果我们暴力去枚举(Ans),复杂度也是(O(N imes A)),考虑优化。

首先有一个很明显的性质就是(Ansle Min(Ai)),即(Ans)至多是(A)中的最小值。

对于(Ans)的判断式:(left lfloor Ai/Ans ight floorge Ai\%Ans)
发现在(Anslesqrt{Ai})时,肯定是恒满足的,因为
(left lfloor Ai/Ans ight floorge sqrt{Ai}ge Ansge Ai\%Ans)
所以所有满足(Anslesqrt{Ai})(Ans)肯定都是可行的(Ans)

考虑(Ans>sqrt{Ai})的情况:
在这种情况下,我们的判断式就会满足(left lfloor Ai/Ans ight floor<sqrt{Ai}<Ans)
所以我们不妨枚举(left lfloor Ai/Ans ight floor)(X)的取值,这样的复杂度是(O(Ncdotsqrt{A})),可以接受。
然后又由于要让(Ans)可行,所以我们要让(left lfloor Ai/Ans ight floorge Ai\%Ans),即(Ans>Xge Y).
考虑满足上述条件下的(Ans)的取值为多少:

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

综上,(Ans=left lfloor frac{Ai}{X} ight floor),特殊的,当(Ai\%X=0)时,(Ans)还有可能为((left lfloor frac{Ai}{X} ight floor-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
",Get());
}
/*
A<=(A/K)*(K+1)
ceil(A/val)-1<=K
*/
原文地址:https://www.cnblogs.com/ftotl/p/11855858.html