9.14做题随记

OI学习,宁可不学不可逆向,要么知道题目怎么做后学习代码写法,要么知道代码基础学习题目怎么做,要么两种都会学习另外一种解法,万万不可逆向学习,费心费力。

P1678 烦恼的高考志愿

题目背景

计算机竞赛小组的神牛 V 神终于结束了高考,然而作为班长的他还不能闲下来,班主任老 t 给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是 v 神太忙了,身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他完成这个艰巨的任务。

题目描述

现有 \(m\) 所学校,每所学校预计分数线是 \(a_i\)。有 \(n\) 位学生,估分分别为 \(b_i\)

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

输入格式

第一行读入两个整数 \(m,n\)

第二行共有 \(m\) 个数,表示 \(m\) 个学校的预计录取分数。

第三行有 \(n\) 个数,表示 \(n\) 个学生的估分成绩。

输出格式

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

输入输出样例 #1

输入 #1

4 3
513 598 567 689
500 600 550

输出 #1

32

说明/提示

数据范围:

对于 \(30\%\) 的数据,\(1\leq n,m\leq10^3\),估分和录取线 \(\leq10^4\)

对于 \(100\%\) 的数据,\(1\leq n,m\leq10^5\),估分和录取线 \(\leq 10^6\) 且均为非负整数。

解析

这道题本身没有什么难度,重点看解法和手写二分

lower_bound解法

STL大好

#include<bits/stdc++.h>
using namespace std;
const int U=1e5+5;
int m,n;
long long a[U],b[U];
long long sum=0;
long long cnt=INT_MAX;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
    #endif

    cin>>m>>n;
    for(int i=1;i<=m;i++) cin>>a[i];
    sort(a+1,a+m+1);
    for(int j=1;j<=n;j++) cin>>b[j];

    for(int i=1;i<=n;i++)
    {
        auto it=lower_bound(a+1,a+m+1,b[i]);
        int u=it-a;
        for(int j=u;j>=u-200&&j>=1;j--) cnt=min(cnt,abs(a[j]-b[i]));
        sum+=cnt;
        cnt=1e9;
    }
    cout<<sum<<endl;

    return 0;
}
// 编译常用指令>> g++ -std=c++14 -O2 -Wall code.cpp -o code

重头戏:手写二分

//手写二分
#include<bits/stdc++.h>
using namespace std;
const int U=1e5+5;
int m,n;
long long a[U],b[U];
long long sum=0;
long long cnt=INT_MAX;
#define mid ((L+R)/2)
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
    #endif

    cin>>m>>n;
    for(int i=1;i<=m;i++) cin>>a[i];
    sort(a+1,a+m+1);
    for(int j=1;j<=n;j++) cin>>b[j];

    for(int i=1;i<=n;i++)
    {
        int L=1,R=m;
        int ans=INT_MAX;
        while(L<=R)
        {
            if(a[mid]==b[i]) {ans=0;break;}
            else if(a[mid]<b[i])
            {
                ans=min(ans,abs(int(a[mid]-b[i])) );
                L=mid+1;
            }
            else if(a[mid]>b[i])
            {
                ans=min(ans,abs(int(a[mid]-b[i])) );
                R=mid-1;
            }
        }
        sum+=ans;
    }
    cout<<sum<<endl;

    return 0;
}
// 编译常用指令>> g++ -std=c++14 -O2 -Wall code.cpp -o code

提炼一下模板

    int L=1,R=m;
    答案初始化;
    while(L<=R)
    {
        if(a[mid]==标准值) {答案处理;break;}
        else if(a[mid]<标准值)
        {
            答案处理;
            L=mid+1;
        }
        else if(a[mid]>标准值)
        {
            答案处理;
            R=mid-1;
        }
    }
    答案累加/答案处理;
posted @ 2025-09-14 11:44  左边之上  阅读(11)  评论(0)    收藏  举报