[算法100天day4]二分查找 练手Ⅲ

非常尴尬的是,我最近由于期末将近,各种无意义的作业接踵而来。所以day3在我的草稿本里难产而死,直接day4啦。
今天是二分查找的第一天

P1102 A-B 数对

还是一样,从基础题开始。这道题可以从简单的方面去想也可以使用STL库的函数,总之简单题多解吧。

题意

给一个N,C和有N个数字的数串,让我们寻找在串里有几个A,B对可以实现A-B=C。

我的解答:
#include <bits/stdc++.h>
#include <cstdio>
#define Max 101
using namespace std;
int n,c;
int num[200005];

int main(){
    cin>> n >>c;
    int cnt = 0;
    for(int i = 0 ; i < n ; i ++){
        cin >> num[i];
    }
    sort(num , num + n);
    
    for(int i = n-1 ; i >= 0 ; i--){
        for(int j = n-1 ; j >= 0; j--){
            if(num[i] - num[j] > c) break;
            else if(num[i] - num[j] == c){
                    cnt++;
            }
            else continue;
        }
    }
    cout<<cnt<<endl;
    return 0;
}

我本意的想法是排序后遍历两遍,如果出现了对于i有J-I>c了,那么就剪枝。
提交后,发现有三个样例TLS不通过,所以寻求更快的方式。

巧妙的暴力题解方式map

A-B=C那不就是A-C=B吗!!!!所以我们只需要利用输入控制即可!
其实也很容易就考虑到,如果对于输入后的数组,还是需要不断地遍历以寻求相等的那两个数的数量。所以!和数量有关,map上场!

题解复现:

#include <bits/stdc++.h>
#include <cstdio>
#define Max 101
using namespace std;
int n,c;
int num[200005];
map<int ,int >m;

int main(){
    cin>> n >>c;
    long long cnt = 0;
    for(int i = 0 ; i < n ; i ++){
        cin >> num[i];
        m[num[i]]+=1;
        num[i] -= c;
    }

    sort(num , num + n);
    for(int i= 0; i<n;i++){
        cnt += m[num[i]];
    }

    cout<<cnt<<endl;
    return 0;
}

最后,对于cnt的范围,如果是200000个1与200000个2的话,最后cnt也是会爆int的。

因为本题用二分太过于。。傻逼了所以next one

P1678 烦恼的高考志愿

又是一道非常简单的题目,本着训练的目的,我准备必用二分来写~
写二分时,一定要弄清楚你要找的那个到底是第一个大于目标数的数还是小于or等于。

#include <bits/stdc++.h>
#include <cstdio>
#define Max 101
using namespace std;
int n,c;
int schooln[100005],studentn[100005];
map<int ,int >m;

int main(){
    int school,student;
    cin>> school >> student;
    long long cnt = 0;
    for(int i = 0 ; i < school ; i ++){
        cin>> schooln[i];
    }
    for(int j = 0 ; j < student ; j ++){
        cin>> studentn[j];
    }
    sort(schooln,schooln + school);
    for(int i = 0 ; i < student ; i ++){
        int j = 0,l = school-1;
        while(j < l){
            int mid = (j+l)/2;
            if(schooln[mid] > studentn[i]){
                l = mid;
            }else{
                j = mid+1;
            }
        }
        if(studentn[i] < schooln[0]) cnt += schooln[0] - studentn[i];
       // else cnt += abs(studentn[i] - schooln[l]);
        else cnt += min(abs(studentn[i] - schooln[l]),abs(studentn[i] - schooln[l-1]));
    }

    cout<<cnt<<endl;
    return 0;
}


!!!在迫不得已的时候再手写二分~我们有lower_bound和uppper_bound啊!!!

P2759 奇怪的函数

题意:我们需要找到一个数x,它的x次方是最先到达n位数字的结果的。输入为n(n<2000000000);因为x的x次方函数必是递增且我们要找的就是在这些里面第一个大于n的数,所以可以试一试二分。
x x ≥ 1 0 n − 1 x^x \ge 10^{n-1} xx10n1
取对数后可以得到:
x ∗ lg ⁡ x ≥ n − 1 x * \lg x \ge n-1 xlgxn1
这个题碰到了一个非常无语的情况,一开始mid * log10(mid)判了两遍,直接TLS了。。。所以不写冗余代码很重要!

#include <bits/stdc++.h>
#include <cstdio>
#define Max 101
using namespace std;
int n,c;
map<int ,int >m;

int main(){
    long long n;
    cin>>n;
    long long l = 0,h = n;
    while(l <= h){
        if(l == h){
            cout<<l<<endl;
            break;
        }
        long long mid = (h+l)/2;
        if(mid * log10(mid) >= n-1){
            h = mid;
        }
        else{
            l = mid+1;
        }
    }

    return 0;
}


咸鱼于2021年5月31日

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值