题目
分析
此题有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);
}