Luogu-P1404 平均数

题目

分析

此题有O(nlogn)做法与O(n)做法,这里只讲O(nlogn)(因为另一种不会
我们可以使用二分(巨佬们的长期经验)来枚举平均数,在check()时将每个数减去平均数后求前缀和,最后判断合法前缀和的差与0的关系。

重点:二分求平均数,化繁为简(不减平均数而每次枚举区间再求平均数常数过大)

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mp(x,y) make_pair(x,y)
using namespace std;
template<typename xxx>void read(xxx &x)
{
    x=0;int f=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
    for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x*=f;
}
template<typename xxx>void print(xxx x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
const int maxn = 200020;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
int n,m;
ll a[maxn];
ll sum[maxn];
inline bool ch(int base) {
	ll pre = 0x7fffffff;
	for(rint i = 1;i <= n; ++i) {
		sum[i] = sum[i - 1] + a[i] - base;
		if(i >= m) {
			if(pre > sum[i - m]) pre = sum[i - m];
			if(sum[i] >= pre) return 1;
		}
	}	
	return 0;
}
int main()
{
	int l = 0,r = 0,mid,ans;
	read(n);read(m);
	for(rint i = 1;i <= n; ++i) {
		read(a[i]);
		a[i] *= 10000;//这里为方便二分都提前*10000,不*1000是计算时保留一位小数以保证精度,所以最后ans/10;
		if(r < a[i]) r = a[i];
	}
	while(l <= r) {
		mid = (l + r) >> 1;
		if(ch(mid)) ans = mid,l = mid + 1;
		else r = mid - 1;
	}
	print(ans/10);
}

posted @ 2019-10-28 16:23  Thomastine  阅读(114)  评论(0)    收藏  举报