【二分】Ybt_最大均值

题目大意

给定正整数序列 A,求一个平均数最大的,长度不小于 L 的(连续的)子段


为了方便计算所以所有数都乘上1000.
Then, 二分均值。

n n n 的范围到 1 0 5 10^5 105
考虑二分判断结果如何在 O ( n ) O(n) O(n) O ( n l o g n ) O(nlogn) O(nlogn) 的复杂度内解决:

我们可以将所有数减去 mid ,然后累计前缀和。
当一段数 a i a_i ai ~ a j ( j < = i − l ) a_j (j <= i-l) aj(j<=il) 的和 S u m [ i ] − S u m [ j ] Sum[i]-Sum[j] Sum[i]Sum[j] 大于0时,则符合条件。
我们可以使取值范围内的 S u m [ j ] Sum[j] Sum[j] 尽量小,遂可以在 O ( n ) O(n) O(n) 内解决拉。


代码

#include<cstdio>
int N, L; 
long long l, r, mid, a[100011], s[100011], ls[100011];
bool check(long long k){
    
    
	for(int i = 1; i <= N; ++i)  //减去mid
	  ls[i] = s[i] - mid * i; 
	long long minn = 0;
	for(int i = L; i <= N; ++i){
    
    
		minn = ls[i-L] < minn? ls[i-L] : minn; //更新Sum_j最小值
		if(ls[i] - minn >= 0) return 1;   //有段数符合条件
	}
	return 0;
}
int main(){
    
    
	scanf("%d%d", &N, &L);
	for(int i = 1; i <= N; ++i){
    
    
		scanf("%lld", &a[i]);
		a[i] = a[i] * 1000;  //方便计算
		s[i] = s[i-1] + a[i];
		r = a[i]>r ? a[i]:r;
	}
	l = s[L] / L;
	while(l < r){
    
      //二分
		mid = (l + r + 1) >> 1;
		if(check(mid)) l = mid;
		else r = mid - 1;
	}
	printf("%lld", l);  //输出
} 

猜你喜欢

转载自blog.csdn.net/qq_42937087/article/details/112383888