题目:
现有 𝑚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,则最后一个就为解
}