题目
有
n
n
n 种颜色的球,第
i
i
i 种球有
a
i
a_i
ai 个,让你把球分成几个集合。
要求:
- 一个集合里的球只能有一种颜色。
- 每两个集合的球的数量相差不能 > 1 >1 >1;
让你求出这些球最少分几个集合。
1
≤
N
≤
500
,
1
≤
a
i
≤
1
0
9
1\le N\le 500,1\le a_i\le 10^9
1≤N≤500,1≤ai≤109
思路
考虑当前每个集合大小为
s
i
z
siz
siz 和
s
i
z
+
1
siz+1
siz+1
显然
s
i
z
siz
siz 越大对我们越优
a
i
=
n
u
m
⋅
s
i
z
+
t
(
0
≤
t
≤
s
i
z
−
1
)
a_i=num\cdot siz+t\quad (0\le t\le siz-1)
ai=num⋅siz+t(0≤t≤siz−1)
那么要满足
n
u
m
≥
t
num\ge t
num≥t ,对于当前
a
i
a_i
ai 是合法的 但不一定是最优的
但是
s
i
z
siz
siz 范围是
1
e
9
1e9
1e9 ,于是不能每个都
O
(
n
)
O(n)
O(n) 检验,考虑分块:
-
当 s i z ≤ n siz\le\sqrt{n} siz≤n 时,那么 n u m ≥ n ≥ s i z > t num\ge\sqrt{n}\ge siz>t num≥n≥siz>t,是合法的,我们就直接取 s i z = n siz=\sqrt{n} siz=n 让答案最大
-
当 s i z > n siz> \sqrt{n} siz>n 时,那么 n u m < n num<\sqrt{n} num<n,由于 s i z siz siz 太大,我们枚举 n u m num num
应该满足 n u m ≥ t ≥ 0 num\ge t\ge 0 num≥t≥0,于是有 s i z = ⌊ a i n u m ⌋ siz=\lfloor\frac{a_i}{num}\rfloor siz=⌊numai⌋
有一种额外情况: t = 0 t=0 t=0
此时 a i a_i ai 一定为 n u m num num 的倍数,于是有 s i z = a i n u m − 1 siz=\frac{a_i}{num}-1 siz=numai−1 也是合法的
考虑当
s
i
z
>
n
siz>\sqrt{n}
siz>n 时候我们只需要检验
M
i
n
a
Mina
Mina 即可
如果我们从小到大枚举
n
u
m
num
num,在
n
u
m
≥
n
num\ge \sqrt{n}
num≥n 时候就会结束,总的次数在
n
\sqrt{n}
n 以内
考虑一组数据
2
1 100
51
证明不能按照上面的算
代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<climits>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define MAXN 500
#define INF 0x3f3f3f3f
LL ans;
int n,a[MAXN+5];
bool check(int x){
x++,ans=0;
for(int i=1;i<=n;i++){
int k=a[i]/x,t=a[i]%x;
if(!t){
ans+=k;
continue;
}
if(k+t<x-1)
return 0;
ans+=k+1;
}
return 1;
}
int main(){
n=read();
int Low=INF;
for(int i=1;i<=n;i++)
a[i]=read(),Low=min(Low,a[i]);
for(int i=1;i<=Low;i++)
if(check(Low/i)||check(Low/i-1)){//这里其实在里面加的1
printf("%lld\n",ans);
return 0;
}
return 0;
}
思考
这种题思维量极大,平时一定要注意锻炼思维