题目链接:https://vijos.org/d/ybttg/p/5c24bad1f41362c9e191275c
时间限制:1000 ms 内存限制:512 MiB
题目描述
原题来自:USACO 2003 Mar. Green
给定一个长度为 的非负整数序列 ,求一个平均数最大的,长度不小于 的子段。
输入格式
第一行用空格分隔的两个整数
和
;
第二行为
个用空格隔开的非负整数,表示
。
输出格式
输出一个整数,表示答案的 倍。不用四舍五入,直接输出。
样例数据
样例输入
10 6
6 4 2 10 3 8 5 9 4 1
样例输出
6500
限制与提示
。
题解
题意:给定一个非负序列,求长度大于F的连续子序列的平均数最大。
思路:二分平均数mid,判断a中是否有长度大于L平均数大于等于mid,再进行调整二分区间。
假设有一个b数组,b[i]=a[i]-mid,当b[i]的区间和大于等于0的时候说明区间平均数大于等于mid。
用sum数组表示b数组前缀和,再求出长度大于等于L的所有区间中的最大区间和=前缀和-前面的最小前缀和(要保证区间长度大于L),判断和是否大于等于0(只要有一个就大于等于0就行)。
Accepted Code:
/*
* @Author: lzyws739307453
* @Language: C++
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const long long inf = 0x3f3f3f3f3f3f3f3f;
int n, m, a[MAXN];
long long sum[MAXN];
struct ios_in {
inline char gc() {
static char buf[MAXN], *l, *r;
return (l == r) && (r = (l = buf) + fread(buf, 1, MAXN, stdin), l == r) ? EOF : *l++;
}
template <typename _Tp>
inline ios_in & operator >> (_Tp &x) {
static char ch, sgn;
for (sgn = 0, ch = gc(); !isdigit(ch); ch = gc()) {
if (!~ch) return *this;
sgn |= ch == '-';
}
for (x = 0; isdigit(ch); ch = gc())
x = (x << 1) + (x << 3) + (ch ^ '0');
sgn && (x = -x);
return *this;
}
}Cin;
struct ios_out {
template <typename _Tp>
inline void operator << (_Tp &x) {
char F[MAXN];
_Tp tmp = x > 0 ? x : (putchar('-'), -x);
int cnt = 0;
while (tmp) {
F[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt) putchar(F[--cnt]);
}
}Cout;
bool Check(int x) {
long long min_ = inf;
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i] - x;
for (int i = m; i <= n; i++) {
min_ = min(min_, sum[i - m]);
if (sum[i] - min_ >= 0)
return true;
}
return false;
}
int main() {
int l = 0, r = 0;
Cin >> n >> m;
for (int i = 1; i <= n; i++) {
Cin >> a[i];
a[i] *= 1000;
r = max(r, a[i]);
}
while (l < r) {
int mid = l + ((r - l + 1) >> 1);
if (Check(mid))
l = mid;
else r = mid - 1;
}
Cout << l, putchar('\n');
return 0;
}