二分专题

目录 

  1. 愤怒的牛
  2. Best Cow Fences 
  3. 曲线
  4. 数列分段 II

链接:https://ac.nowcoder.com/acm/contest/951/A
来源:牛客网
 

题目描述

农夫约翰建造了一座有n间牛舍的小屋,牛舍排在一条直线上,第i间牛舍在xi的位置,但是约翰的m头牛对小屋很不满意,因此经常互相攻击。约翰为了防止牛之间互相伤害,因此决定把每头牛都放在离其它牛尽可能远的牛舍。也就是要最大化最近的两头牛之间的距离。

牛们并不喜欢这种布局,而且几头牛放在一个隔间里,它们就要发生争斗。为了不让牛互相伤害。John 决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是多少呢?

输入描述:

 

第一行用空格分隔的两个整数n和m;

第二行为n个用空格隔开的整数,表示位置 xi

输出描述:

输出仅一个整数,表示最大的最小距离值。

示例1

输入

复制

5 3
1 2 8 4 9

输出

复制

3

说明

把牛放在1,4,8这样最小距离是3 。

备注:

2≤n≤105 ,0≤xi≤109。

思路 : 要求最小距离尽可能大, 二分牛舍之间的距离,安排 m 个牛的位置,如果满足m 个牛舍之间的距离大于等于二分答案, 则答案在右侧,继续缩小范围,否则 答案在左侧。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std ;
typedef long long LL ;
const int MAX = 100005 ;
int n , m ;
int a[MAX] ;
bool check(int x) {
	int cnt = 1 ;
	int t = 1 ;
	for(int i = 1 ; i<=n ; i++ ) {
		if(a[i] - a[t] >=x) {
			cnt++ ;
			t = i ;
		}
		if(cnt == m ) return true ;
	}
	
	return false;
}
int main(){
	cin >> n >> m ;
	int maxx = -0x3f3f3f3f  ;
	for(int i = 1 ; i<=n ; i++ ) {
		scanf("%d",&a[i]);
		maxx = max(maxx,a[i]) ;
	}
	int l = 1 , r = maxx ;
	sort(a+1,a+1+n) ;
	while(l

链接:https://ac.nowcoder.com/acm/contest/951/B
来源:牛客网
 

题目描述

给定一个长度为n的非负整数序列A,求一个平均数最大的,长度不小于L的子段。

输入描述:

第一行用空格分隔的两个整数n和L;
第二行为n个用空格隔开的非负整数,表示Ai。

输出描述:

输出一个整数,表示答案的1000倍。不用四舍五入,直接输出。

示例1

输入

复制

10 6
6 4 2 10 3 8 5 9 4 1 

输出

复制

6500

备注:

1≤n≤1051 ,0≤Ai≤20000 。

将问题转化成 存不存在一个 长度大于等于 L 的序列和 大于0 ,求最大的. 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std ;
typedef long long LL ;
const int MAX = 100005 ;
int n ,L ;
double a[MAX] ;
double sum[MAX] ;
bool check(double avg) {
	for(int i = 1 ; i<=n ; i++ ) {
		sum[i] = sum[i-1] + a[i] -avg ;
	}
	double minn = 0 ;
	for(int i = 0  ,j = L ;  j<=n ;j++,i++){
		minn = min(minn,sum[i]) ;
		if(sum[j]-minn >=0) return true ;
	}
	return false ;
}
int main(){
	cin >> n  >> L ;
	double l = 0 , r = 2000 ;

	for(int i = 1 ; i<=n ; i++ ) {
		cin>> a[i] ;
		r = max(r,a[i]) ;
	}

	while(r -l >1e-5){
		double mid = (l+r)/2 ;
		if(check(mid)){
			l = mid ;
		}
		else{
			r = mid ;
		}

	}
	printf("%d\n",(int)(r*1000));

	return 0 ;
}

链接:https://ac.nowcoder.com/acm/contest/951/C
来源:牛客网
 

题目描述

明明做作业的时候遇到了n个二次函数Si(x)=ax2+bx+c  ,他突发奇想设计了一个新的函数F(x)=max⁡{Si(x)},i=1…nF(x)= \max \{ S_i (x) \},i=1 \ldots nF(x)=max{Si​(x)},i=1…n。

二分专题_第1张图片

明明现在想求这个函数在[0,1000]的最小值,要求精确到小数点后四位,四舍五入。

输入描述:

输入包含T组数据,每组第一行一个整数n;

接下来n行,每行3个整数a,b,c,用来表示每个二次函数的3个系数。注意:二次函数有可能退化成一次。

输出描述:

每组数据输出一行,表示新函数F(x)的在区间[0,1000]上的最小值。精确到小数点后四位,四舍五入。

示例1

输入

复制

2
1
2 0 0
2
2 0 0
2 -4 2

输出

复制

0.0000
0.5000

备注:

对于50%50\%50%的数据,1≤n≤100;对于100%的数据,1≤T≤101,1≤n≤105。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std ;
typedef long long LL ;
const double inf = 0x3f3f3f3f ;
const int MAX = 100005 ;
int n ;
int a[MAX] ,b[MAX] ,c[MAX] ;
double check(double x ) {
	double sum = - inf ;
	for(int i = 1 ; i<=n ; i++) {
		sum = max(sum,(a[i]*x*x + b[i]*x +c[i])*1.0) ;
	}
	return sum ;
}

int main(){
	int T ;
	cin >>T;
	while(T--) {
		scanf("%d",&n);
	
		for(int i = 1 ; i<=n ; i++) {
			scanf("%d%d%d",&a[i],&b[i],&c[i]) ;
		}
		double l = 0 , r = 1000 ;
		while(r-l >1e-6 ){
			double lm = l+(r-l)/3.0 ;
			double rm = r-(r-l)/3.0 ;
			if(check(lm) >check(rm) ) {
				l = lm ;
			}
			else r = rm ;
		}
		printf("%.4lf\n",check(l));
		
	}

	return 0 ;
}

 

链接:https://ac.nowcoder.com/acm/contest/951/D
来源:牛客网
 

题目描述

对于给定的一个长度为N的正整数数列A,现要将其分成M段,并要求每段连续,且每段和的最大值最小。
例如,将数列4  2  4  5  14 要分成3段:
若分为[42][45][1],各段的和分别为6,9,1,和的最大值为9;
若分为[4][24][51],各段的和分别为4,6,6,和的最大值为6;
并且无论如何分段,最大值不会小于6。
所以可以得到要将数列4  2  4  5  14 要分成3段,每段和的最大值最小为6。

输入描述:

第1行包含两个正整数N,M;
第2行包含N个空格隔开的非负整数AiA_iAi​,含义如题目所述。

输出描述:

仅包含一个正整数,即每段和最大值最小为多少。

示例1

输入

复制

5 3
4 2 4 5 1

输出

复制

6

备注:

对于20%的数据,有N≤10N;
对于40%的数据,有N≤1000N ;
对于100%的数据,有N≤105N NM≤N,AiA_iAi​之和不超过10^。

思路 : 二分最大值 , check函数判断 是否存在一个序列使得每一段和 都小于等于 最大值 。

#include 
#include 
#include 
#include 
#include 
using namespace std ;
typedef long long LL  ;
const int MAX = 1000115 ;
int n , m ;
int a[MAX] ;
int sum ;
bool check(int x ){
	int k = 0 ;
	int num = 1 ;
	for(int i = 1 ; i<=n ; i++ ) {
		if(k+a[i] > x) {
			k = 0 ;
			num++ ;
		}
		k+=a[i] ;
		if(k >x )return false ;
	}
	
	return num<=m ;
}
int main(){

	cin >> n >> m ;
	for(int i = 1 ; i<=n ; i++ ) {
		cin >> a[i] ;
		sum+=a[i] ;
	}
	int l = 0 , r = sum ;
	while(l +1 

 

你可能感兴趣的:(牛客网,#,基础算法------二,分)