普通视图

Received before yesterday

2025–ACM&TC第三次招新赛题解

作者George
2025年11月2日 20:13

2025--ACM&TC第三次招新赛题解

题目难度:

签到:9、12

简单:2、5、8、11

中等:3、4、7

困难:1、6、10

题解

1、中位数

题目给出的n为奇数,那么最终的中位数一定是中间的那个数,于是我们可以二分答案,不断地去枚举答案

#include <bits/stdc++.h>
using namespace std;
#define int long long

int a[200005];
int n, k;

bool check(int x) {
    int sum = 0;
    int m = (n + 1) / 2; 
    for (int i = m; i <= n; i++) {
        if (a[i] < x) {
            sum += x - a[i];  
            if (sum > k) return 1; 
        }
    }
    return sum > k;  
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n); 

    int l = a[(n + 1) / 2], r = 1e18;  
    while (l + 1 < r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            r = mid; 
        } else {
            l = mid; 
        }
    }
    cout << l << '\n';  

}

2、怕挂科的George

这题考的就是结构体的排序,也是看看一些人补没补题,如果第一场招新赛的第 4 题没写出来但补了的话,这一题也是肯定能写出来的。然后就是平均数记得开float或者double,感觉会有很多人开int然后WA好多发(学长赛前预测),学长出题的时候专门手搓了几个卡 int 的数据,嘿嘿~。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

struct stus{
    int s,a;
}stu[105];

bool cmp(stus c,stus d){
    return c.s<d.s;
}

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    int n,m;
    cin>>n>>m;
    double sum=0;
    for(int i=1;i<=n;++i){
        cin>>stu[i].s>>stu[i].a;
        sum+=stu[i].a;
        if(stu[i].s==m&&stu[i].a<60)
            stu[i].a=60;
    }
    double avg=sum/n;
    for(int i=1;i<=n;++i){
        if(stu[i].s!=m&&stu[i].a>=avg){
            stu[i].a=max(stu[i].a-2,0);
        }
    }
    sort(stu+1,stu+n+1,cmp);
    for(int i=1;i<=n;++i){
        cout<<stu[i].a<<" ";
    }
    cout<<endl;
    return 0;
}

3、位运算终于来了

这道题你首先要清楚 异或运算是什么,当前位相同为0,不同为1,这样根据这个规律我们可以在a的当前位与b的当前位不同时让a去异或2的当前位次幂(1,10,100,1000....),比如a:(1001), b: (110),当枚举到第1位(从后往前)a为0,b为1那需要让a异或2的1次方,可以让a的当前位变为1,这样你会发现当到达当前位枚举过的位都是相同的,如果枚举到2的k次方大于a,那么不可能让a最终等于b,当然还有别的做法

#include <bits/stdc++.h>
using namespace std;
#define int long long

int ksm(int a, int b){
    int ans = 1;
    while(b){
        if(b % 2){
            ans = ans * a;
        }
        b = b / 2;
        a = a * a;
    }
    return ans;
}
void solve(){
    int a, b;
    cin >> a >> b;
    if(a == b){
        cout << 0 << '\n';
        return;
    }
    int aa = a;
    vector<int> ans;
    string s;
    for(int i = 0;; i++){
        if (a == 0 && b == 0) break;
        int x = ksm(2, i);
        if((a & 1) != (b & 1)){
            ans.push_back(x);
            if(x > aa){
            cout << -1 << '\n';
            return;
        }
        }
        a = a >> 1;
        b = b >> 1;
    }
    cout << ans.size() << '\n';
    for(auto t : ans){
        cout << t << ' ';
    }
    cout << '\n';
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int t;
    cin >> t;
    while(t--){
        solve();
    }
}

4、我要打瓦!颗秒!!棒棒棒棒!!!

这题考的就是你们高中学的n的平方的前n项和通项公式(不知道你们老师有没有让背过,大部分老师应该都让背过)。不要觉得这题很奇怪,数学在计算机及 ACM 中很重要,说白了对于 ACM 来说编程语言只是工具,解题思路大部分都是靠数学思维,包括你们学的高数,和以后学的线代、离散、概率论等都会是 ACM 的考点(我记得去年招新赛,我们学长给我们出了一道二项式定理,感兴趣的自己可以看一下),计算机和数学相关性很大的,比如数学中的离散和计算机中的数据结构重合度很高,内容大部分都一样。这题的题解废话有点多了,主要也是想要让你们了解一下数学和计算机的关系,下面是正式题解:

随便举几个例子画画图就能知道移动的路线尽可能往中间靠才能让 ans 最大化,所以使 ans 最大化的路线就是先向右再向下,这样一直循环到 (n,n) 。通过下面两个重要的数学公式,可以推导出答案为:n * (n + 1) * (4 * n - 1) / 6。需要注意此题除法放在最后,避免前面没除尽,出现小数造成误差,模数 2022 最后可以和分母 6 约分成 337 ;还有就是边运算边取模,因为计算过程中会超出 long long 的范围 1e18 ;以及n也需要开long long ,因为n参与下面ans的计算了。具体计算过程见下图,黄线和就是n的平方的前n项和通项公式,橙线和则可以拆成等差数列的前n项和通项公式n的平方的前n项和通项公式的和。

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

const int mod=1e9+7;

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        long long n;
        cin>>n;
        long long ans=337*n%mod*(n+1)%mod*(4*n-1)%mod;
        cout<<ans<<endl;
    }
    return 0;
}

5、带派不老铁?

起始位置由 ( 0 , 0 ) 到 ( x , y ) ,其结果只有三种情况。
1.输出结果为-1:当x=y或x=y+1或y=1时,此时一定不满足题目要求,输出-1;
2.输出结果为2:满足y>x即可
3.输出结果为3:剩下的情况都是3步

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int x,y;
        cin>>x>>y;
        if(x==y||x==y+1||y==1)
            cout<<-1<<endl;
        else if(x<y)
            cout<<2<<endl;
        else
            cout<<3<<endl;
    }
    return 0;
}

//
// ⠀⠀⠀             ⠀⢸⣿⣿⣿⠀⣼⣿⣿⣦⡀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀ ⠀⢸⣿⣿⡟⢰⣿⣿⣿⠟⠁
// ⠀⠀⠀⠀⠀⠀⠀⢰⣿⠿⢿⣦⣀⠀⠘⠛⠛⠃⠸⠿⠟⣫⣴⣶⣾⡆
// ⠀⠀⠀⠀⠀⠀⠀⠸⣿⡀⠀⠉⢿⣦⡀⠀⠀⠀⠀⠀⠀ ⠛⠿⠿⣿⠃
// ⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣦⠀⠀⠹⣿⣶⡾⠛⠛⢷⣦⣄⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣧⠀⠀⠈⠉⣀⡀⠀ ⠀⠙⢿⡇
// ⠀⠀⠀⠀⠀⠀⢀⣠⣴⡿⠟⠋⠀⠀⢠⣾⠟⠃⠀⠀⠀⢸⣿⡆
// ⠀⠀⠀⢀⣠⣶⡿⠛⠉⠀⠀⠀⠀⠀⣾⡇⠀⠀⠀⠀⠀⢸⣿⠇
// ⢀⣠⣾⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⢀⣼⣧⣀⠀⠀⠀⢀⣼⠇
// ⠈⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠋⠙⠛⠛⠛⠛⠛⠁
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⡿⠋⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⢾⠿⠋ 
//

6、搜索板子题

和题目名一样,就是搜索板子题, BFS 和 DFS 都能写,这里放的是 BFS 的AC码,主要就是让学会搜索的人都能AC,所以也没涉及任何思维,就纯板子。考虑到这是你们培训讲的最难的算法,估计有好多人还没学,所以归到了困难题。

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

typedef pair<int, int> pii;

int w, h;
char graph[1001][1001];
bool visited[1001][1001];

int cnt = 0;

void bfs(int startx, int starty) {
    queue<pii> q;
    q.push({startx, starty});
    visited[startx][starty] = true;
    cnt++;

    int dx[] = {-1, 0, 1, 0};
    int dy[] = {0, 1, 0, -1};

    while (!q.empty()) {
        int currentx = q.front().first;
        int currenty = q.front().second;
        q.pop();

        for (int i = 0; i < 4; ++i) {
            int newx = currentx + dx[i];
            int newy = currenty + dy[i];

            if (newx >= 0 && newx < h && newy >= 0 && newy < w && graph[newx][newy] == '.' && !visited[newx][newy]) {
                q.push({newx, newy}); 
                visited[newx][newy] = true;
                cnt++;
            }
        }
    }
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);

    int startx, starty;
    cin >> w >> h;

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            cin >> graph[i][j];
            if (graph[i][j] == '@') {
                startx = i;
                starty = j;
            }
        }
    }

    bfs(startx, starty);
    cout << cnt << endl;

    return 0;
}

7、数好数字

这题是一个简单数论,虽然难度不高,但由于是数论我们还是把它归为了中等题。

大概就是根据好数的周期性,以210为周期,每个210内的好数数量都一样。

先计算一下 2 到 r 的好数数量,再计算一下 2 到 l 的好数数量,然后一减就是 l 到 r 的好数数量。

注意开long long!!!

#include <iostream>
using namespace std;
#define endl "\n"

const int LCM = 210; // 2*3*5*7=210

// 判断一个数是否不被2、3、5、7中的任何一个整除
bool good(int x) {
    return x % 2 > 0 && x % 3 > 0 && x % 5 > 0 && x % 7 > 0;
}

// 计算[0, x)范围内满足good条件的数字数量
int get_naive(int x) {
    int ans = 0;
    for (int i = 1; i <= x; ++i) {
        if (good(i)) {
            ans++;
        }
    }
    return ans;
}

// 优化计算:利用210是2、3、5、7的最小公倍数,减少重复计算
long long get(long long r) {
    return (r / LCM) *48 + get_naive(r % LCM);
}  

int main() {
    int t;
    cin >> t;

    while (t--) {
        long long l, r;
        cin >> l >> r;
        // 计算[l, r]范围内满足条件的数字数量
        cout << get(r) - get(l-1) << endl;
    }

    return 0;
}

8、什么?你...你竟然是尊贵的传奇王者?

简单数学题,由奇+奇=偶、偶+偶=偶、奇+偶=奇,所以只需统计一下奇偶数量,如果奇偶数量相等,则就能恰好分割,则输出 “ Yes ” ,否则输出 “ No ” 。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

int a[205]={};

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int cntj=0,cnto=0;
        int n;
        cin>>n;
        for(int i=0;i<2*n;++i){
            cin>>a[i];
            if(a[i]%2==1)
                cntj++;
            else
                cnto++;
        }
        if(cntj==cnto)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;

    }
    return 0;
}

9、这是什么图形

这是一道小学题,正方形的性质可知对角线相等,那么一半都相等

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        int l, r, d, u;
        cin >> l >> r >> d >> u;
        if (l == r && d == u && l == d) {
            cout << "Yes\n";
        } else {
            cout << "No\n";
        }
    }
    return 0;
}

10、haxin学姐的旅程规划

让我们把陈述中给出的等式变形重新写成 $c{i+1}−b{c{i+1}}=c{i}−b{c{i}}$ 。这意味着我们旅行计划中路径上的所有城市将具有相同的 $i−b_{i}$ 值,即索引值减去对应的美丽值,这个性质可以通过上面那种对题目中的等式进行变形得到,也可以通过画图得知,就自己画两个线段然后就能琢磨出来。

这题用到C++的一个map容器,没学过的学一下,这个容器挺重要的,大概就是能将两个量关联起来。这一题的思路就是先遍历一遍数组b,并用map的第一个参数放 $i−b{i}$ 值,将 $i−b{i}$ 值相同的元素的值累加起来存到第二个参数中,这样就把 $i−b{i}$ 值和与它相对应的美丽值之和关联在一起了,通过第一个参数的值就能直接访问到与之对应的第二个参数的值。此外,把数组从头遍历到尾,就是满足了题目中序列严格递增的要求。最后再遍历一遍map,map中最大的第二个参数值就是答案,即最大美丽值。另外,数据范围上,虽然n和 $b{i}$ 都没超过 int 范围,但是答案有可能将 n 个 $b_{i}$ 相加,这就超过了 int 范围,所以要开long long,map的第二个参数和 ans 都要开 long long。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

int b[200050]={};

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    int n;
    cin>>n;
    map<int,long long>mapp;
    for(int i=1;i<=n;++i){
        cin>>b[i];
    }
    int x;
    for(int i=1;i<=n;++i){
        x=i-b[i];
        mapp[x]+=b[i];
    }
    long long ans=0;
    for(auto p:mapp){
        if(p.second>ans)
            ans=p.second;
    }
    cout<<ans<<endl;
    return 0;
}

11、挑剔的猫

思路:在开始之前,我们先求出所有元素的绝对值,因为它们的符号并不重要。然后,如果数组的第一个元素等于或小于数组的[n/2]+1最小元素,则答案是可能的。否则,答案就是不可能的

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
int a[N];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int f=abs(a[1]);
        int cnt=0;
        for(int i=2;i<=n;i++){
            int z=abs(a[i]);
            if(z<=f)
                cnt++;
        }
        if(cnt+1<=(n/2+1))
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

12、这是啥博弈?

诈骗题,提示里也提醒了,输出获胜者名字的第一个字母,而两个人的第一个字母都是 ’ B ‘ ,所以直接输入n,然后直接输出 ’ B ‘ 就行了。但对于这题来说,也可以不用输入 n ,直接输出 ’ B ‘ ,因为AC的标准就是只看你输出的数据和后台的数据是否能完全吻合,不看输入。不要觉得这种诈骗题很奇怪,这都是我们平常碰到过的,很多比赛都有,比如我们学校前年举办的新生河南省邀请赛里就有一道,如果感兴趣的话,可以看看。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
    cout<<'B'<<endl;
    return 0;
}

//
// ⠀⠀⠀             ⠀⢸⣿⣿⣿⠀⣼⣿⣿⣦⡀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀ ⠀⢸⣿⣿⡟⢰⣿⣿⣿⠟⠁
// ⠀⠀⠀⠀⠀⠀⠀⢰⣿⠿⢿⣦⣀⠀⠘⠛⠛⠃⠸⠿⠟⣫⣴⣶⣾⡆
// ⠀⠀⠀⠀⠀⠀⠀⠸⣿⡀⠀⠉⢿⣦⡀⠀⠀⠀⠀⠀⠀ ⠛⠿⠿⣿⠃
// ⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣦⠀⠀⠹⣿⣶⡾⠛⠛⢷⣦⣄⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣧⠀⠀⠈⠉⣀⡀⠀ ⠀⠙⢿⡇
// ⠀⠀⠀⠀⠀⠀⢀⣠⣴⡿⠟⠋⠀⠀⢠⣾⠟⠃⠀⠀⠀⢸⣿⡆
// ⠀⠀⠀⢀⣠⣶⡿⠛⠉⠀⠀⠀⠀⠀⣾⡇⠀⠀⠀⠀⠀⢸⣿⠇
// ⢀⣠⣾⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⢀⣼⣧⣀⠀⠀⠀⢀⣼⠇
// ⠈⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠋⠙⠛⠛⠛⠛⠛⠁
// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⡿⠋⠀
// ⠀⠀⠀⠀⠀⠀⠀⠀⢾⠿⠋ 
//

二分专题

作者George
2025年8月14日 15:55

注意:
        1、专题系列难度随机。由于有些OJ网站不易被打开,无法查看原题目,所以所有的题目链接都指向VJ(Virtual Judge)中对应的题目。VJ中有题目的原出处,需要的自取!
        2、为了让大家更易于理解AC码,每一道题的代码风格都用AI进行了优化。


A、跳石头(洛谷 P2678)

题目链接:跳石头(洛谷 P2678)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n" 

int L, N, M;
int rock[50050];

bool check(int distance) {
    int removed = 0;
    int prerock = 0;
    for (int i = 0; i < N; ++i) {
        if (rock[i] - prerock < distance) {
            removed++;
        } else {
            prerock = rock[i];
        }
    }
    if (L - prerock < distance) {
        removed++;
    }
    return removed <= M;
}

int bsearch() {
    int  l = -1, r = L;
    while (l + 1 != r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return l;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> L >> N >> M;
    for (int i = 0; i < N; ++i) {
        cin >> rock[i];
    }
    if (N == 0 && M == 0) {
        cout << L << endl;
    } else {
        cout << bsearch() << endl;
    }
    return 0;
}    

B、木材加工(洛谷 P2440)

题目链接:木材加工(洛谷 P2440)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

int n, k;
int logs[100050];
int maxx = 0;

bool check(int mid) {
    if (mid == 0) {
        return true;
    }
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
        cnt += logs[i] / mid;
    }
    return cnt >= k;
}

int bsearch() {
    int l = -1, r = maxx;
    while (l + 1 != r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return l;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> k;
    for (int i = 0; i < n; ++i) {
        cin >> logs[i];
        maxx = max(maxx, logs[i]);
    }
    cout << bsearch() << endl;
    return 0;
}    

C、Set or Decrease(CodeForces 1622C)

题目链接:Set or Decrease(CodeForces 1622C)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long

int a[200050], presum[200050];
int n, k;

bool cmp(int x, int y) {
    return x > y;
}

bool check(int mid) {
    for (int i = 0; i <= min(mid, n - 1); i++) {
        int mi = a[n] - (mid - i);
        int sum_ = presum[n - 1] - presum[i] + (i + 1) * mi;
        if (sum_ <= k) {
            return true;
        }
    }
    return false;
}

int bsearch(int sum, int k) {
    int l = -1, r = sum - k;

    while (l + 1 != r) {
        int mid = (l + r) / 2;

        if (check(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }

    return r;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;

    while (t--) {
        cin >> n >> k;
        int sum = 0;

        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum += a[i];
        }

        sort(a + 1, a + 1 + n, cmp);

        for (int i = 1; i <= n; i++) {
            presum[i] = presum[i - 1] + a[i];
        }

        if (sum <= k) {
            cout << 0 << endl;
        } else {
            int ans = bsearch(sum, k);
            cout << ans << endl;
        }
    }

    return 0;
}

D、Ice Cream Balls(CodeForces 1862D)

题目链接:Ice Cream Balls(CodeForces 1862D)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

long long n;

bool check(long long x) {
    long long temp = x * (x - 1) / 2;
    return temp <= n;
}

long long bsearch() {
    long long l = -1, r = 2e9;
    while (l + 1 != r) {
        long long mid = (l + r) / 2;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return l;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;
    while (t--) {
        cin >> n;
        if (n == 1) {
            cout << 2 << endl;
            continue;
        }
        long long result = bsearch();
        cout << result + (n - (result * (result - 1) / 2)) << endl;
    }
    return 0;
}

E、Vika and the Bridge(CodeForces 1848B)

题目链接:Vika and the Bridge(CodeForces 1848B)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

bool check(int mid, const vector<int>& pos, int n) {
    int m = pos.size();
    int last = -1;
    int repaint = 0;

    for (int i = 0; i < m; ++i) {
        int gap = pos[i] - last - 1;
        if (gap > mid) {
            repaint++;
            if (repaint > 1) {
                return false;
            }
            if (gap / 2 > mid) {
                return false;
            }
        }
        last = pos[i];
    }

    int gap = n - pos.back() - 1;
    if (gap > mid) {
        repaint++;
        if (repaint > 1) {
            return false;
        }
        if (gap / 2 > mid) {
            return false;
        }
    }

    return true;
}

int bsearch(const vector<int>& pos, int n) {
    int l = -1, r = n;

    while (l + 1 != r) {
        int mid = (l + r) / 2;

        if (check(mid, pos, n)) {
            r = mid;
        } else {
            l = mid;
        }
    }

    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;

    while (t--) {
        int n, k;
        cin >> n >> k;

        vector<int> c(n);
        for (int i = 0; i < n; ++i) {
            cin >> c[i];
        }

        vector<vector<int>> pos(k + 1);
        for (int i = 0; i < n; ++i) {
            pos[c[i]].push_back(i);
        }

        int ans = n;

        for (int color = 1; color <= k; ++color) {
            if (pos[color].empty()) {
                continue;
            }

            int min_max_step = bsearch(pos[color], n);
            ans = min(ans, min_max_step);
        }

        cout << ans << endl;
    }

    return 0;
}

F、Interview(CodeForces 1807E)

题目链接:Interview(CodeForces 1807E)

标签:二分

AC码:

#include <iostream>
using namespace std;
#define endl "\n"

const int MAXN = 100005;
int cows[MAXN];
int n, f;

bool check(double mid) {
    double presum[MAXN] = {};
    double min_sum = 0;

    for (int i = 1; i <= n; ++i) {
        presum[i] = presum[i - 1] + cows[i - 1] - mid;
    }

    for (int i = f; i <= n; ++i) {
        min_sum = min(min_sum, presum[i - f]);
        if (presum[i] - min_sum >= 0) {
            return true;
        }
    }

    return false;
}

double bsearch() {
    double l = 0, r = 2000;

    while (r - l > 1e-5) {
        double mid = (l + r) / 2.0;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }

    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> f;
    for (int i = 0; i < n; ++i) {
        cin >> cows[i];
    }

    double result = bsearch();
    cout << int(result * 1000) << endl;

    return 0;
}

G、Chat Ban(CodeForces 1612C)

题目链接:CodeForces 1612C

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

long long k, x;

bool check(long long mid) {
    if (mid <= k) {
        return (1 + mid) * mid / 2 >= x;
    }
    return (1 + k) * k / 2 + (k - 1 + 2 * k - mid) * (mid - k) / 2 >= x;
}

long long bsearch() {
    long long n = 2 * k - 1;
    long long l = -1, r = n;
    while (l + 1 != r) {
        long long mid = (l + r) / 2;
        if (check(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        cin >> k >> x;
        long long result = bsearch();
        cout << result << endl;
    }
    return 0;
}

H、Pursuit(CodeForces 1530C)

题目链接:Pursuit(CodeForces 1530C)

标签:二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

int n;
vector<int> a, b;

bool cmp(int x, int y) {
    return x > y;
}

bool check(int mid) {
    int num = (n + mid) - (n + mid) / 4;
    int suma = 0, sumb = 0;
    vector<int> backupa = a;
    vector<int> backupb = b;

    for (int i = 0; i < mid; ++i) {
        backupa.push_back(100);
        backupb.push_back(0);
    }

    sort(backupa.begin(), backupa.end(), cmp);
    sort(backupb.begin(), backupb.end(), cmp);

    for (int i = 0; i < num; ++i) {
        suma += backupa[i];
        sumb += backupb[i];
    }

    return suma < sumb;
}

int bsearch() {
    int l = -1, r = 2 * n + 1;
    while (l + 1 != r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;
    while (t--) {
        a.clear();
        b.clear();
        cin >> n;

        int score;
        for (int i = 0; i < n; ++i) {
            cin >> score;
            a.push_back(score);
        }

        for (int i = 0; i < n; ++i) {
            cin >> score;
            b.push_back(score);
        }

        sort(a.begin(), a.end(), cmp);
        sort(b.begin(), b.end(), cmp);

        int sum1 = 0, sum2 = 0;
        for (int i = 0; i < n - n / 4; ++i) {
            sum1 += a[i];
            sum2 += b[i];
        }

        if (sum1 > sum2) {
            cout << 0 << endl;
        } else {
            cout << bsearch() << endl;
        }
    }
    return 0;
}

I、Best Cow Fences(POJ 2018)

题目链接:Best Cow Fences(POJ 2018)

标签:浮点二分

AC码:

#include <iostream>
using namespace std;
#define endl "\n"

const int MAXN = 100005;
int cows[MAXN];
int n, f;

bool check(double mid) {
    double presum[MAXN] = {};
    double min_sum = 0;

    for (int i = 1; i <= n; ++i) {
        presum[i] = presum[i - 1] + cows[i - 1] - mid;
    }

    for (int i = f; i <= n; ++i) {
        min_sum = min(min_sum, presum[i - f]);
        if (presum[i] - min_sum >= 0) {
            return true;
        }
    }

    return false;
}

double bsearch() {
    double l = 0, r = 2000;

    while (r - l > 1e-5) {
        double mid = (l + r) / 2.0;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }

    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> f;
    for (int i = 0; i < n; ++i) {
        cin >> cows[i];
    }

    double ans = bsearch();
    cout << int(ans * 1000) << endl;

    return 0;
}

J、平均数(洛谷 P1404)

题目链接:平均数(洛谷 P1404)

标签:浮点二分

AC码:

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

double a[1000050], sum[1000050];
int n, m;

bool check(double mid) {
    for (int i = 1; i <= n; i++) {
        sum[i] = sum[i - 1] + (a[i] - mid);
    }

    double mi = 1e16;
    for (int i = m; i <= n; i++) {
        mi = min(mi, sum[i - m]);
        if (sum[i] - mi >= 0) {
            return true;
        }
    }
    return false;
}

int bsearch() {
    double l = 0, r = 1e9;
    while (r - l > 1e-7) {
        double mid = (l + r) / 2.0;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return r * 1000;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    cout << bsearch() << endl;

    return 0;
}

K、

题目链接:

标签:二分+DFS/BFS,选最合适的一种

AC码:

L、Drying(POJ 3104)

题目链接:Drying(POJ 3104)

标签:二分

AC码:

#include <iostream>
#include <algorithm>
using namespace std;
#define endl "\n"

int n, k;
int a[100010];

bool check(int mid) {
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        if (a[i] > mid) {
            sum += (a[i] - mid + k - 2) / (k - 1);
        }
        if (sum > mid) {
            return false;
        }
    }
    return true;
}

int bsearch() {
    int l = -1, r = a[n - 1];
    while (l + 1 != r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    while (cin >> n) {
        for (int i = 0; i < n; ++i) {
            cin >> a[i];
        }
        cin >> k;

        sort(a, a + n);

        if (k == 1) {
            cout << a[n - 1] << endl;
            continue;
        }

        int ans = bsearch();
        cout << ans << endl;
    }
    return 0;
}

二分(算法基础)

作者George
2025年8月14日 15:51

注意:为了归纳分类,有些文章的标题中带小括号,小括号里的内容对应于OI Wiki网站中的目录:oi-wiki.org(若小括号中有大于号">",则表示此文章的内容处于">"后面的子目录中,或者子目录的子目录中...


前言

        你们可能在其他地方看到了很多版本各种各样的二分板子,me too,都很麻烦,一会l=mid+1,一会r=mid+1,特别容易错。直到一个学姐给我们分享了小破站up主“五点七边”的一个视频,她说她一直都用的这个板子。这是一个左开右闭区间 (l, r] 形式的二分查找模板,看了之后,感觉这个板子确实容易理解,还能避免死循环。
视频链接:二分查找为什么总是容易写错?

一、板子

1、二分答案:

注意:必要时可以将(l + r) / 2改为l + (r - l) / 2,可以防止数据溢出long long的范围。比如,如果l是1e18,r是1e18 + 1000,那么r - l就是1000,除以2就是500,加上l得到1e18 + 500,这显然不会溢出,而直接相加的话1e18 + 1e18 + 1000就会溢出。

bool check(int mid) {

}

int bsearch() {
    int l = -1, r = n;

    while (l + 1 != r) {
        int mid = (l + r) / 2;

        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }

    return l or r; // 根据题目判断
}

2、浮点二分:

注意:浮点二分一般用于让结果乘以1000之类的数再输出的题。例如,之前发的二分专题中的I题J题

bool check(double mid) {

}

int bsearch() {
    double l = 0, r = 1e9;
    while (r - l > 1e-9) {   //这里的精度根据题目而定
        double mid = (l + r) / 2.0;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid;
        }
    }
    return r;
}
❌