POJ 2018. Best Cow Fences

有关数据#

Time Limit Memory Limit Difficulty
1 sec 30000 K 31100

题目大意#

给定长度为 N 正整数数列 A, 求一个平均数最大的、长不小于 L 的(连续的)子段。

提示#

  • 1N105
  • 0LN
  • NAiN

解法分析#

二分答案,将问题转换为是否存在一个平均数小于 mid 且长度不小于 L 的子段
如果把序列上的每个数都减去 mid,则问题转化成寻找和大于等于 0 且长度不小于 L 的子段。
考虑 O(n2logn) 的做法。我们需要求出所有长度符合条件的子段中和最大的,存不存在全看这个最大的和是否非负。(很容易理解吧)那么,枚举字段左右区间,答案就是 maxLiN{sumimin0jiL{sumj}}
显然时间复杂度不允许。注意到左边的 min0jiL{sumj} 可以在第一层循环 i 里递推求出。
所以,我们就可以 O(n) 解决 check 的问题。至此,整道题就解决了。

AC Code#

# include <iostream>
using namespace std;

# define ll long long
# define lf double
# define int ll
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB push_back
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second

CI maxn = 1e6 + 7;

int n, k;
lf a[maxn]; 
lf b[maxn];
lf sum[maxn];

signed main(){
	cin >> n >> k;
	GO (i, 1, n) scanf("%lf", &a[i]);
	lf l = -1e6, r = 1e6;
	lf eps = 1e-5;
	while (r - l > eps){
		lf mid = (l + r) / 2.0;
		GO (i, 1, n) b[i] = a[i] - mid;
		GO (i, 1, n) sum[i] = sum[i - 1] + b[i];
		lf chk = -2e18;
		lf min_val = 2e18;
		GO (i, k, n){
			min_val = min(min_val, sum[i - k]);
			chk = max(chk, sum[i] - min_val);
		}
		if (chk >= 0){
			l = mid;
		}
		else{
			r = mid;
		}
	}
	cout << (int)(r * 1000);
	return 0;
}

作者:DE_aemmprty

出处:https://www.cnblogs.com/aemmprty/p/BestCowFences.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   DE_aemmprty  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示