第1部分 基礎算法(提高篇)--第2章 二分與三分1434:【例題2】Best Cow Fences

1434:【例題2】Best Cow Fences

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 1579 通過數: 638
【題目描述】
給定一個長度爲n的正整數序列A。求一個平均數最大的,長度不小於L的子序列。

【輸入】
第一行,n和L;

n個正整數,表示A。

【輸出】
一個整數,表示答案的1000倍(不用四捨五入,直接輸出)。

【輸入樣例】
10 6
6 4 2 10 3 8 5 9 4 1
【輸出樣例】
6500
【提示】
n ≤ 100000


思路:
假設在序列中存在一段數, sum 爲這段數的總和(sum=k個a[i]之和), k 爲這段數的數字個數,那麼這段數的平均數就是 sum/k ,且 k>=L ,當存在 ans<=sum/k 時,就說明當前的 ans 小了,需要變得更大,就是二分中的 “left=mid+1” ,否則就 “right=mid-1”

現在把上面的 ans<=sum/k 轉換一下式子,將 k 乘到左邊去,得到了 ansk<=sum ,再把sum移到左邊去,變成了 ansk-sum<=0 ,兩邊同時乘以 -1 ,得到
sum-ansk>=0
=>k個a[i]之和-ans
k>=0
=>k(a[i]-ans)>=0

二分答案 ans,判斷 ans 是要更大還是更小才能最接近最終答案
1、將每個 a[i] 都減去 ans,做一遍前綴和
2、枚舉 右端點r ,尋找在 r-L左邊的 左端點l,使得 前綴和r-前綴和l 最小,就是尋找在 r-L 左邊的 最小前綴和
3、如果 前綴和r-前綴和l>=0 , ans 還可以更大,否則 ans 還要更小
4、輸出最終的 ans
————————————————

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6;
int n,L;
double l=-1e6,r=1e6,d=1e-5,pre[N],a[N],b[N];  
void init()
{
	scanf("%d%d",&n,&L);
	for (int i=1;i<=n;i++) scanf("%lf",&a[i]);
}
bool check(double m)
{
	double min_left=1e10,anss=-1e10; //min_left:最小前綴和 
	for (int i=1;i<=n;i++) b[i]=a[i]-m;
	for (int i=1;i<=n;i++) pre[i]=pre[i-1]+b[i];//pre[]:前綴和數組 
	for (int r=L;r<=n;r++) //一個小貪心,從L開始枚舉右端點
	{
		min_left=min(min_left,pre[r-L]);//不斷更新符合條件的最小前綴和
		if (pre[r]-min_left>=0) return true;
	} 
	return false;
}
double Binarysearch()
{
	while (r-l>d) //實數域上的二分 
	{
		double mid=(l+r)/2;
		if (check(mid)==true) l=mid; //check():判斷ans是否還能更大 
		else r=mid; 
	}
	return r; 
}
int main()
{
	init();
	cout<<(int)(Binarysearch()*1000)<<endl;
	return 0;
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章