POJ 2018 【二分答案+dp求最大区间段】

题目链接: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;
 } 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值