简述题意:n个队员n个实力值,可能相同可能为负,让你进行分组:使其人数最少的组人数最大化。分组规则是什么呢:实力值连续,且不重复,比如1,2,3 5,6,7这是两组而非1,2,3,3或1,2,4,5。
题意描述得很清楚了,看看输入输出要求开始作答。
思路:看到“最大最小”“最多最少”这样非常别扭的标志性词句,第一反应肯定是二分了,但是二分啥?一个看似很顺的思路就是直接二分答案,从0到1e5二分最小值,但是我们都知道二分核心就是check函数,如果这样做那就需要check当前的一个mid作为人数最小组的人数,也就是看看那个人数最少的组人数可不可以是mid值,将给定mid作为已知测试情况…………可以想想,很难想出来该如何check。
不行,就换:可不可以直接模拟?试一试,要分组,我一个一个地将数挑出来,到可以去且最应该去的组,什么叫可以去,就是连续的,当前数字是可以链到已有数组上的,不是首就是尾,什么叫最应该去,就是在可以去的组别中要去到人数最少的组。
很明显这是一个贪心的思想,每一次都取当前最优情况…………具体地,用一个q数组存每一组的最大值,用一个s数组存每一组的人数,二者是严格对应的。首先,sort给定数组,为什么要sort,马上会说;之后,遍历每一个值(x)插入到某一组,怎么办,遍历q数组来找x+1(链在尾端,因为sort从小到大升序),找得到插进去(并且一定插到最后一个q[x+1]来实现插到人数最少的组中),找不到另开新组;最后,遍历就得到最小的s。
but,会超时…………怎么优化,在遍历q数组时用二分,为什么可以用二分查找,也就是说为什么q一定升序,为什么一定插到最后一个q[x+1],1 2 3 4 4 5 5 8 用这个模拟一遍q,s数组的更新过程就明白了。
1 2 3 4 4 5 5 8
q 1+1+1+1+1 4+1 8 先生者必然居上,取之尽锱铢
s 1+1+1+1+1 1+1 1
code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;
int p[N],s[N],kn[N];
int ans=INT_MAX;
int bin(int l,int r,int i){
//if(l>r)return 0;
while(l<r){
int mid=l+r>>1;
if(p[mid]>=kn[i])r=mid;
else l=mid+1;
}
return r;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>kn[i];
sort(kn+1,kn+1+n);
//p[1]=kn[1]+1,s[1]++,m++;
for(int i=1;i<=n;i++){
int now=bin(1,m,i);
while(p[now+1]==p[now]&&now<=m)now++;
if(p[now]!=kn[i]||now>m) s[++m]=1,p[m]=kn[i]+1;
else s[now]++,p[now]++;
}
for(int i=1;i<=m;i++){
//cout<<p[i]<<" ";
ans=min(ans,s[i]);
}
cout<<ans<<endl;
return 0;
}