[Acwing] 102. Zuijia牛围栏 二分答案

前言

加把劲 !
传送门 :

思路

这道题如果是普通做法,显然就是一个个枚举出来,必然是不可能这么做的

所以我们可以用二分来优化查找过程 :

二分无非就是分为以下两种 :

  • 二分答案
  • 二分查找

二分查找是查找左右区间 : 对于这题来说显然不可能

二分答案 , 我们发现有一个平均值可以做来二分

所以我们可以试着二分答案,但是二分答案最难的是在 c h e c k check check里面

那么我们怎么 c h e c k check check呢 ? 学过图论的朋友应该知道

对于这种求题,我们一般可以使用前缀和来求解 s u m [ i ] − m i d sum[i]-mid sum[i]mid

因为这样子可以将问题转化为,是否有一段区间满足 s u m [ i ] − m i d > 0 sum[i]-mid>0 sum[i]mid>0

所以当我们处理完前缀和之后,我们就可以使用,双指针来就,枚举区间

但是显然,比 F F F 大的区间也是可以取的,所以我们需要每次记录一个极小值

CODE

const int N  = 1e5+10;
const double eps = 1e-5;

double a[N];
double sum[N];

int n,m;

bool check(double x)
{
	for(int i=1;i<=n;i++)
	{
		sum[i] = sum[i-1]+a[i] - x;	
	}
	
	double minn = 0 ;
	for(int i = 0, j = m;j<=n;j++,i++)
	{
		minn  = min(minn,sum[i]);
		if(sum[j] - minn >= 0 )return true;
	}
	return false;
}

void solve()
{
	cin>>n>>m;
	double l = 1, r = 0 ;
	
	for(int i = 1;i<=n;i++)
	{
		cin>>a[i];
		r =max(r,a[i]);
	}
	
	 while(r - l > eps)
	 {
		 double mid = (l+r)/2;
		 if(check(mid)) 
		 l = mid;
		 else
		r = mid;
	 }

	 cout<<(int)(r*1000)<<endl;
	
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值