题目链接:http://poj.org/problem?id=2018
从0到2000000(2000*1000) 枚举平均值,让数组统一减去枚举的平均值,如果存在区间和大于等于0的,就说明答案是成立的。
关键是如果求最大的区间和。
假设不限制区间的长度,求某一个数组的最大区间和应该怎么求?
如果dp[i]表示的是某左界到右界 i 的最大区间和,那么dp[i+1] 应该如果求?
因为要求是连续的序列,所以dp[i+1]只可能有两种选择去得到右界为i+1的最大区间和,第一种是a[i]加上以i为右界的最大区间和,第二种是什么都不加,以自身为最大区间和(也就是区间长度为1),那么 dp[i+1] = max(a[i], dp[i]+a[i])。
如果限制了区间长度,我们只需要把n个数当1个数来处理就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int Maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
int a[Maxn];
long long sum[Maxn];
bool ok(int x, int F, int n) {
int L = 0, R = 0, cur = F-1;
long long ans;
sum[cur] = 0;
while(R < F) sum[cur] += a[R++]-x;
while(R < n) {
sum[cur+1] = sum[cur]-a[L++]+a[R++];
cur++;
}
ans = sum[F-1];
for(int i = F; i < n; ++i) {
sum[i] = max(sum[i], sum[i-1]+a[i]-x);
ans = max(ans, sum[i]);
}
if(ans >= 0) return true;
else return false;
}
int main(void)
{
int N, F;
scanf("%d%d", &N, &F);
for(int i = 0; i < N; ++i) {
scanf("%d", &a[i]);
a[i] *= 1000;
}
int L = 0, R = 2000000, mid;
while(L < R) {
int mid = (L+R+1)/2;
if(ok(mid, F, N)) L = mid;
else R = mid-1;
}
printf("%d\n", L);
return 0;
}