P1678 烦人的高考志愿

题目:

现有 𝑚m 所学校,每所学校预计分数线是 𝑎𝑖ai​。有 𝑛n 位学生,估分分别为 𝑏𝑖bi​。

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

输入描述

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

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

输出描述

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

输入样例

4 3
513 598 567 689
500 600 550

输出样例

32

解析:

先说一下对这道题的理解,如果要找与目标数最进的数就要考虑a[mid]等于目标数的情况;

所以在find函数中等于的话直接返回零;

因为mid=l+r>>1;(或者l+r+1>>1)a[mid]肯定比a[l]或者a[r]离目标数更近;

但是不能还和之前的二分模板一样,因为之前的暂停条件是l=r;

但是如果想找离目标数最近的数的话,只有四种情况

(1)目标数比最小的还小

(2)目标数比最大的还大

(3)目标数等于数组中的某个元素

(4)目标数在数组中的两个元素之间;

对于(4)解决办法是当

mid=l+r>>1;(mid=l+r+1>>1;)

if(a[mid]>x)r=mid;

else l=mid;

或者

if(a[mid]<x)l=mid;

else r=mid;

因为不必须寻找等于目标数的元素,所以l和r不一定要相同;

所以上面的模板l=mid,r=mid;因为mid肯定比l和r更接近;

如果等于了直接返回零;

然后这样写的话第(1)(2)直接包含了

写个例子

(1)

1 5 8;

如果求2

第一次循环mid=2;a[mid]=5>2;

l=1,r=2;

a[l]=1,a[r]=5;

没有第二次循环因为r=l+1;

(2)

1 5  6 9  10;

如果求2

第一次循环mid=3;a[mid]=6>2;

l=1,r=3;

a[l]=1,a[r]=6;

第二次循环mid=2;a[mid]=5>2;

l=1,r=2;

a[l]=1,a[r]=5;

结束(l+1=r)

(3)

1 5  6 9  10;

如果求7

第一次循环mid=3;a[mid]=6<7;

l=3,r=5;

a[3]=4,a[5]=10;

第二次循环mid=4;a[mid]=9>2;

l=3,r=4;

结束(l+1=r)

给个题解

#include<iostream>
#include<algorithm>
using namespace std;
int a[1000005], b[1000005], m, n;
int find(int x) {
	int l, r;
	l = 0, r = m - 1;
	while (l < r - 1) {
		int mid = l + r>> 2;//或者l+r+1>>1都一样
		if (a[mid] == x) {
			return 0;
		}
		if (a[mid] > x)r = mid;
		else
			l = mid;
	}
	return min(abs(x - a[r]), abs(x - a[l]));
}
int main() {
	cin >> m >> n;
	for (int i = 0; i < m; i++) {
		cin >> a[i];
	}
	sort(a, a + m);
	for (int j = 0; j < n; j++) {
		cin >> b[j];
	}
	long long ans = 0;
	for (int j = 0; j < n; j++) {
		ans = ans + find(b[j]);
	}
	cout << ans;
	return 0;
}

补充俩题解

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1e5 + 10;
long long a[N], x, sum, n, m;

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	sort(a + 1, a + n + 1); //排序勿忘 
	a[0] = -1e12; a[n + 1] = 1e12;	 //最后再解释

	while (m--)
	{
		cin >> x;
		int l = 0, r = n ;	//r设为n
		while (l < r) //寻找第一个超过估分的学校,那它或它前面的一个学校就是目标学校 
		{
			int mid = l + r + 1 >> 1;
			if (a[mid] <= x) l = mid;
			else r = mid - 1;
		}
		if (x - a[l] <= a[l + 1] - x) sum += x - a[l];
		else sum += a[l + 1] - x;
	}

	cout << sum;
	return 0;
	//a[0]=-1e12: 所有分数先可能都比估分大,那么L就为0,L+1就为0,故设a[0]为无穷小,则第一个值就为解 
	//a[n+1]=1e12: 所有分数线可能都比估分小,那么l就为n,a[n+1]-x无穷大,则设a[n+1]为无穷大,
				//并将l设为0,r=n如此,l最大为n,则最后一个就为解 
}
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
long long a[N],x,sum,n,m;

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1); //排序勿忘 
	a[0]=-1e12;a[n+1]=1e12;	 //最后再解释
	
	while(m--)
	{
		cin>>x;
		int l=1,r=n+1;	//r设为n+1 
		while(l<r) //寻找第一个超过估分的学校,那它或它前面的一个学校就是目标学校 
		{
			int mid=l+r>>1;
			if(a[mid]>=x) r=mid;
			else l=mid+1;
		}
		if(a[l]-x<=x-a[l-1]) sum+=a[l]-x;
		else sum+=x-a[l-1];
	}
	
	cout<<sum;
	return 0;
	//a[0]=-1e12: 所有分数先可能都比估分大,那么l就为1,n-1就为0,故设a[0]为无穷小,则第一个值就为解 
	//a[n+1]=1e12: 所有分数线可能都比估分小,那么l就为n,a[l]-x可能为负,则设a[n+1]为无穷大,
				//并将r设为n+1,如此,l最大为n+1,则最后一个就为解 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值