P4447 [AHOI2018初中组] 分组 题解

简述题意: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;
}

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值