• 【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
    */
    
  • 相关阅读:
    条件语句实例
    数据类型
    C#与.NET概述
    c#循环
    语句
    数组

    英文文献中的数学符号
    如何计算协方差、 协方差矩阵 、 相关系数 、 马氏距离
    opengl 笔记
  • 原文地址:https://www.cnblogs.com/ftotl/p/11855858.html
Copyright © 2020-2023  润新知