算法设计与编程 烦恼的高考志愿 知识点:二分

142 阅读2分钟

P1678 烦恼的高考志愿 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)P1678 烦恼的高考志愿 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题刚开始没看明白,求所有学生不满意度和的最小值,我以为是把每个学生与各个录取线的差值相加,求一个最小值。

后来看样例看明白了:

image.png 我们需要根据学生预估分与找与它差值最小的录取线: 也就是 把每个学生的预估分每个录取线相减,求出最小差值,这样不满意度最小。

最后把所有差值和相加,得到的就是不满意度和的最小值。

解题思路

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005], b[100005];
int n, m;
int ans;
signed main()
{
	cin.tie(nullptr)->sync_with_stdio(false);
	cin>>n>>m;
	for(int i=0;i<n;i++)cin>>a[i];
	for(int i=0;i<m;i++)cin>>b[i];
	  sort(a,a+n);//排序
	
		for(int j=0;j<m;j++)  //估分 
		{	int tol=INT_MAX;
		  for(int i=0;i<n;i++)  //学校录取线每次都要全部遍历一次 ,找出与估分差值最小的
     	  { 
			tol=min(tol,abs(a[i]-b[j])); 
		  }
		ans+=tol;
     	}
cout<<ans;
	return 0;
}

image.png

n,m最大1e5,两层循环就超时了,所以可以用二分去找,二分是OnlognO(nlogn):

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005], b[100005];
int n, m;
int ans;
signed main()
{
	cin.tie(nullptr)->sync_with_stdio(false);
	cin>>n>>m;
	for(int i=0;i<n;i++)cin>>a[i];
	for(int i=0;i<m;i++)cin>>b[i];
	  sort(a,a+n);//排序
	//开始二分查找

	for(int i=0;i<m;i++)
	{
		 int l=0,r=n-1,tol=0x7fffffff;
		while(l<=r)
		{
		   int mid=l+r>>1;
		   
		   if(a[mid]<b[i]) 
		   {
		   	 tol=min(tol,abs(b[i]-a[mid]));
		   	 l=mid+1;
		   }
		   else
		   {
		   	r=mid-1;
		   	tol=min(tol,abs(b[i]-a[mid]));
		   }
		}
	 ans+=tol;
	}

   cout<<ans<<endl;
	return 0;
}

image.png