二分的定义

首先要明白这个算法的运用范围 首先要明白这个算法的运用范围 首先要明白这个算法的运用范围
二分是用于查找一个数在这个数列中所在的位置 , 二分是用于查找一个数在这个数列中所在的位置, 二分是用于查找一个数在这个数列中所在的位置,
比一般的 f o r 直接暴力查找要快 比一般的for直接暴力查找要快 比一般的for直接暴力查找要快
其原理在于将数组分为 2 个部分 其原理在于将数组分为2个部分 其原理在于将数组分为2个部分
并依次用这个数的大小找出这个数在哪个区间,找到直接停止 并依次用这个数的大小找出这个数在哪个区间,找到直接停止 并依次用这个数的大小找出这个数在哪个区间,找到直接停止
但是二分在特殊情况下才能使用 但是二分在特殊情况下才能使用 但是二分在特殊情况下才能使用
条件就是这个数列必须是一个递增序列 条件就是这个数列必须是一个递增序列 条件就是这个数列必须是一个递增序列
明白了这些,我们给道例题 : 明白了这些,我们给道例题: 明白了这些,我们给道例题:
备注:例题来源于洛谷

题目背景

计算机竞赛小组的神牛 V 神终于结束了高考,然而作为班长的他还不能闲下来,班主任老 t 给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是 v 神太忙了,身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他完成这个艰巨的任务。

题目描述

现有 m m m 所学校,每所学校预计分数线是 a i a_i ai 。有 n n n 位学生,估分分别为 b i b_i bi

根据 n n n 位学生的估分情况,分别给每位学生推荐一所学校,要求学校的预计分数线和学生的估分相差最小(可高可低,毕竟是估分嘛),这个最小值为不满意度。求所有学生不满意度和的最小值。

输入格式

第一行读入两个整数 m m m n n n m m m 表示学校数, n n n 表示学生数。

第二行共有 m m m 个数,表示 m m m 个学校的预计录取分数。第三行有 n n n 个数,表示 n n n 个学生的估分成绩。

输出格式

输出一行,为最小的不满度之和。

输入输出样例

输入#1

4 3
513 598 567 689
500 600 550

输出#1

32

说明/提示

数据范围:

对于 30 30 30% 的数据, 1 ≤ n , m ≤ 1000 1\leq n,m\leq1000 1n,m1000,估分和录取线 ≤ 10000 \leq10000 10000

对于 100 100 100% 的数据, 1 ≤ n , m ≤ 100000 1\leq n,m\leq100000 1n,m100000,估分和录取线 ≤ 1000000 \leq 1000000 1000000 且均为非负整数。

题目传送门 题目传送门 题目传送门

分析:

由于 n n n很大普通算法查找需要 O ( n O(n O(n m ) m) m)的时间复杂度

暴力算法无法满足100%的数据要求

这时候就该用二分了

二分的时间复杂度是 O ( m O(m O(m l o g n ) logn) logn)

为满足其所需条件在前面加上一个 s o r t sort sort即可

实现代码如下: 实现代码如下: 实现代码如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define int long long
int a[10000001],sum,m,n;
//主函数外的变量初值为0
int erfen(int x){
	int l=1,r=m,Min=190000000000000000;
	while(l<=r){
		int y=(l+r)/2;
		if(abs(a[y]-x)<=Min){
			Min=abs(a[y]-x);
		}
		if(x<a[y]){
			r=y-1;
		}else{
			l=y+1;
		}
	}
	return Min;
}//也可以不用函数的直接写在main里
signed main(){
	cin>>m>>n;
	for(int i=1;i<=m;i++)
		cin>>a[i];
	sort(a+1,a+1+m);//快速排序使其变为递增序列
	for(int i=1;i<=n;i++){
		int b;
		cin>>b;
		sum+=erfen(b);
	}
	cout <<sum;
 	return 0;
}

~ 完结撒花 完结撒花 完结撒花 ~

附:这个是第一个博客,也是比较粗糙
先从最简单的算法开始

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐