文章目录
- 题目
- 思路
- 代码
- 思考
题目
有 nnn 种颜色的球,第 iii 种球有 aia_iai? 个,让你把球分成几个集合。
要求:
- 一个集合里的球只能有一种颜色。
- 每两个集合的球的数量相差不能 >1>1>1;
让你求出这些球最少分几个集合。
1≤N≤500,1≤ai≤1091\le N\le 500,1\le a_i\le 10^91≤N≤500,1≤ai?≤109
思路
考虑当前每个集合大小为 sizsizsiz 和 siz+1siz+1siz+1
显然 sizsizsiz 越大对我们越优
ai=num?siz+t(0≤t≤siz?1)a_i=num\cdot siz+t\quad (0\le t\le siz-1)ai?=num?siz+t(0≤t≤siz?1)
那么要满足 num≥tnum\ge tnum≥t ,对于当前 aia_iai? 是合法的 但不一定是最优的
但是 sizsizsiz 范围是 1e91e91e9 ,于是不能每个都 O(n)O(n)O(n) 检验,考虑分块:
-
当 siz≤nsiz\le\sqrt{n}siz≤n? 时,那么 num≥n≥siz>tnum\ge\sqrt{n}\ge siz>tnum≥n?≥siz>t,是合法的,我们就直接取 siz=nsiz=\sqrt{n}siz=n? 让答案最大
-
当 siz>nsiz> \sqrt{n}siz>n? 时,那么 num<nnum<\sqrt{n}num<n?,由于 sizsizsiz 太大,我们枚举 numnumnum
应该满足 num≥t≥0num\ge t\ge 0num≥t≥0,于是有siz=?ainum?siz=\lfloor\frac{a_i}{num}\rfloorsiz=?numai???
有一种额外情况: t=0t=0t=0
此时 aia_iai? 一定为 numnumnum 的倍数,于是有 siz=ainum?1siz=\frac{a_i}{num}-1siz=numai???1 也是合法的
考虑当 siz>nsiz>\sqrt{n}siz>n? 时候我们只需要检验 MinaMinaMina 即可
如果我们从小到大枚举 numnumnum,在 num≥nnum\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)){
//这里其实在里面加的1printf("%lld\n",ans);return 0;}return 0;
}
思考
这种题思维量极大,平时一定要注意锻炼思维