洛谷官方题单P1678 烦恼的高考志愿 题解

洛谷官方题单P1678 烦恼的高考志愿
思路:将学校分数排序后,找出离学生分数的最近的左边界和右边界,将两个边界点与学生分数求差,再取min

注:要开long long

法1

#include 
#include 
#include 

using namespace std;

const int N = 100010;

int a[N], b[N];
int n, m;
long long ans;

int main ()
{
    cin >> n >> m;
    
    for(int i = 0; i < n; i ++) cin >> a[i];
    for(int j = 0; j < m; j ++) cin >> b[j];
    
    sort(a, a + n);
    
    for(int i = 0; i < m; i ++)
    {
        int l = 0, r = n - 1;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(b[i] >= a[mid]) l = mid;
            else r = mid - 1;
        }
        // printf("--%d\n", a[l]);
        int res = abs(b[i] - a[l]);
        
        l = 0, r = n - 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(b[i] <= a[mid]) r = mid;
            else l = mid + 1;
        }
        // printf("==%d\n", a[l]);
        int t = abs(b[i] - a[l]);
        if(res > t) res = t;
        
        ans += res;
    }
    
    printf("%llf ", ans);
    
    return 0;
}

法2

#include 
#include 
#include //头文件
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;//结束程序
}

你可能感兴趣的:(洛谷官方提单,算法,c++,数据结构)