二分 算法入门

 

//洛谷P1182 数列分段 Section II
//最小的最大值,二分答案模板题 
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1E5+10;
int n, m, a[maxn], l=0, r=0, mid;
bool check(int target){
	int temp=0,cnt=1;
	for(int i=0;i<n;i++){
		if(temp+a[i]<=target){//不许超过指定和,这里在二分答案 
			temp+=a[i];
		}else{
			temp=a[i];//新开一段 
			cnt++; 
		}
	} 
	return cnt<=m;//小于要求m段则成功 
}
int main(){
//	freopen("5.in","r",stdin);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>a[i];
		l=max(l,a[i]);//所有分段可能最小和 
		r+=a[i];//所有分段可能里最大和 
	}
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid)){
			r=mid-1;//右边界先收缩,但是这个mid可能是答案,所以循环以l==r+1结束 
		}else{
			l=mid+1;
		}
	}
	cout<<l;
	return 0;

}

//http://ybt.ssoier.cn:8088/problem_show.php?pid=1433愤怒的牛
//最大的最小值,二分模板题 
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1E5+10;
int n, m, a[maxn], l=0, r=0, mid;
bool check(int target){
	int pre=a[0],cnt=1;
	for(int i=1;i<n;i++){
		if(a[i]-pre<target){//不许短于指定距离,这里在二分答案 
			continue;
		}else{
			pre=a[i];//可以此处安置一头牛了 
			cnt++; 
		}
	} 
	return cnt>=m;//大于要求距离能安置足够多牛则成功 
}
int main(){
//	freopen("5.in","r",stdin);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n); 
	l=a[n-1];
	for(int i=1;i<n;i++)	l=min(l,a[i]-a[i-1]);//最小距离 
	r=a[n-1]-a[0];//最大距离 
	while(l<r){
		mid=(l+r+1)>>1;
		if(check(mid)){
			l=mid;//缩短左边界但是又要保留,所以mid倾向更大+1 
		}else{
			r=mid-1; 
		}
	}
	cout<<l;
	return 0;

}

 //https://www.luogu.com.cn/problem/P10450
//二分浮点数+前缀和均值优化查找大于L子序列
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1E5+10;
int n, L;
double a[maxn], sum[maxn], l=maxn, r=0, mid, eps=1E-5;
bool check(double target){
	for(int i=1;i<=n;i++){//枚举不同大于L的子序列,相当于枚举两端点O(n^2) 
		sum[i]=sum[i-1]+a[i]-target;//很容易想到前缀和,这里特殊在每一项数列减去均值求前缀和
	}
	double temp=0; 
	for(int i=L;i<=n;i++){
		temp=min(temp, sum[i-L]);//存下前缀和最小的左端点 
		if(sum[i]>=temp){//求和(ai-均值) >=0,存在大于L的子序列均值大于target 
			return true;
		}
	} 
	return false;
}
int main(){
//	freopen("5.in","r",stdin);
	cin>>n>>L;
	a[0]=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		r=max(r,a[i]);
		l=min(l,a[i]);
	}
	while(l+eps<r){//二分找平均数,注意不搞eps就超时 
		mid=(l+r)/2;
		if(check(mid)){
			l=mid;
		}else{
			r=mid; 
		}
	}
//	cout<<l<<check(l) ;
	cout<<int(r*1000);//其实check(r)是false但是l有精度误差选择这样输出 
	return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值