0
点赞
收藏
分享

微信扫一扫

烦恼的高考志愿

Brose 2022-03-20 阅读 34
算法

题目描述

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

输入格式

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

输出格式

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

测试样例

输入

4 3
513 598 567 689
500 600 550

输出

32

题目提示

对于 30 % 30\% 30% 的数据, m , n ≤ 1 0 3 m,n≤10^3 m,n103,估分和录取线 ≤ 1 0 4 ≤10^4 104;

对于 100 % 100\% 100% 的数据, n , m ≤ 1 0 5 n,m≤10^5 n,m105,估分和录取线 ≤ 1 0 6 ≤10^6 106

思路:

这道题如果使用二分思路会很简单。
首先,将每个学校的录取分数线从大到小排序。
接着开始二分查找:
我们应该查找每个学校录取分数线中最后一个小于等于每个同学分数的数,可以用一个while循环来模拟二分查找。
复杂度为O(m*log(n));

#include <iostream>
#include <cmath>
#include <algorithm>//头文件

using namespace std;//名字空间

int a[100100], b[100100];//定义两个数组,分别储存每个学校的分数线,和每个同学的估分

int main()//主函数
{
	int n, m;//定义n,m
	cin >> n >> m;//输入
	for(int i = 1; i <= n; i++)
	{
		cin >> a[i];//输入
	}
	for(int i = 1; i <= m; i++)
	{
		cin >> b[i];//还是输入
	}
	sort(a + 1, a + n + 1); //把每个学校的分数线从小到大排序
	int ans = 0;  //答案一开始为0,因为要累加和。
	for(int i = 1; i <= m; i++)
	{
		int l = 0, r = n + 1;//定义左边界与右边界
		while(l < r)
		{
			int mid = (l + r) / 2;//取查找范围的中间值
			if(a[mid] <= b[i])//如果录取分数线数组中的第mid个元素小于或等于那位同学的分数
			{
				l = mid + 1;//左边界就往右移
			}
			else
			{
				r = mid;//右边界就往左移
			}
		}
		if(b[i] <= a[1])//这里需要特判断一下,不然只能得70分
		{
			ans += a[1] - b[i];
		}
		else
		{
			ans += min(abs(a[l - 1] - b[i]), abs(a[l] - b[i]));//加上两个绝对值中最小
		}
	}
	cout << ans;//输出ans
	return 0;//结束程序
}
举报

相关推荐

0 条评论