NOIP2023模拟2联测23 集训

题目大意

给定 n n n个数 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an,你需要找到一个集合 S S S,使得 S S S严格大于 S S S的平均数的数字个数尽量多,输出最多的个数。

注意:这里的集合是可重集,数字可以重复。

1 ≤ n ≤ 1 0 6 , 1 ≤ a i ≤ 1 0 9 1\leq n\leq 10^6,1\leq a_i\leq 10^9 1n106,1ai109


题解

首先,我们将 a a a从小到大排序。

枚举第一个严格大于 S S S的平均数的数 i i i。因为比平均数小的数肯定越多越好,所以我们可以取 1 1 1 i − 1 i-1 i1之间的所有数。

为了让平均数尽量小,在选择严格大于 S S S的平均数的数的时候肯定要选尽量小的数。也就是说,严格大于 S S S的平均数的数是 a i a_i ai a i a_i ai之后的连续的一段数,设这段数是 a i a_i ai a p a_p ap,那也就是说我们要选择的数是 a 1 a_1 a1 a p a_p ap,这里的 p p p需要满足 s u m p p < a i \dfrac{sum_p}{p}psump<ai(其中 s u m p p \dfrac{sum_p}{p} psump指这 p p p个数的平均数),也就是 s u m p < a i × p sum_psump<ai×p。为了使严格大于 S S S的平均数的数更多,我们需要求满足条件的最大的 p p p

我们发现,满足条件的最大的 p p p是随 i i i的增大而增大(或者不变)的,那么我们可以用一个指针来求 p p p。对于每个 i i i和其对应的 p p p,严格大于 S S S的平均数的数的数量为 p − i + 1 p-i+1 pi+1,用 p − i + 1 p-i+1 pi+1来更新答案即可。

时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

code

#include
using namespace std;
const int N=1000000;
int n,p=1,ans=0,a[N+5];
long long sum[N+5];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+a[i];
	}
	for(int i=1;i<=n;i++){
		while(p+1<=n&&sum[p+1]<1ll*(p+1)*a[i]) ++p;
		ans=max(ans,p-i+1);
	}
	printf("%d",ans);
	return 0;
}

你可能感兴趣的:(题解,题解,c++)