题目

分析

此题有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);
}
01-11 19:19