CF1539C Stable Groups 题解

题目大意

现在有 \(n\) 个学生,每个学生的水平为 \(a_i\),允许你往其中添加 \(k\) 个任意水平的学生。现在要求你把这 \(n\) 个学生分成几组,使得每一组中的水平大小相邻的学生的水平绝对差小于等于 \(x\)

思路分析

考虑贪心

可以先对学生的水平排一下序,算绝对差,把绝对差存储到一个数组里,接着对这个绝对差数组做贪心。

如何贪心

因为绝对差小的情况更容易满足,所以我们要先对绝对差数组排序,使得绝对差小的情况先考虑,绝对差大的情况后考虑。

如果绝对差大于 \(x\),可以用两种办法解决:

  • 能用加学生解决的,就用加学生解决。(并且要使得加的学生尽量少)
  • 不能用加学生解决的,可以直接分成两组,避免两个人在同一组内。

代码剖析

3.1:差分

sort(a+1,a+n+1);
	for(int i=2;i<=n;i++){
		b[i-1]=a[i]-a[i-1];
	}
sort(b+1,b+n);

\(b\) 数组存储了两个水平相邻学生的绝对差,这里可以不带绝对值,因为 \(sort\) 的结果是从小到大的。

最后对 \(b\) 数组排序,以便后面做贪心。

3.2:贪心

for(int i=1;i<n;i++){
	if(b[i]>x){//如果需要操作
		if(k>=(b[i]-1)/x){//看一看可不可以通过加学生解决
			k-=(b[i]-1)/x;//可以就让可用学生减掉需要学生
		}
		else{
			cnt++;//否则就分组,分组的次数加1。
		}
	}
}

首先判断这个差是否需要操作,如果不需要,就不管了。

如果需要,先尝试用加学生的办法去做。

  • WARNING:这里减掉 \(1\) 是非常重要的。我们可以把学生看成隔板,把一段水平差分成几段,而段数比点数少 \(1\)

如果学生够用,把可用学生数量减去需要的学生数量。

否则就分一次组,让分组次数的计数器加 \(1\)

最后直接输出。

  • WARNING:输出 \(cnt+1\)!因为 \(cnt\) 记录的是分组的次数,分了 \(cnt\) 次,就会有 \(cnt+1\) 组。

AC Code

代码已分段给出,不给出完整代码

CF AC记录

洛谷AC记录

posted @ 2022-01-26 17:45  Shunpower  阅读(34)  评论(0编辑  收藏  举报