前言

最近要考试了嘛,所以整整基础知识。

正文

二分查找

二分查找是 C++ 中的基础算法,在一个有序数列中查找一个数非常实用。

举个例子,在一个单调上升序列中找一个数(\(x\))的位置。

第一种方法,暴力一个个的找,复杂度 \(O(n)\)

第二种方法,二分查找:二分查找顾名思义,先找到数列的中间下标 \(mid\)(查找方法:l/*左端点下标*/+r/*右端点下标*/>>1),然后把 \(a_{mid}\)\(x\) 比较看看它比 \(a_{mid}\) 大还是小,如果大就在 \(mid\) 的右边查找,代码实现:l=mid,mid=l+r>>1;;如果小就在 \(mid\) 的左边查找,代码实现:r=mid,mid=l+r>>1;。时间复杂度 \(O(\log n)\)

例题代码就不给了。

二分答案

跟二分查找差不多,只不过这个是把已知答案范围二分,找到 \(mid\),再将 \(mid\) 代入函数中看看得出的答案比给出的答案大还是小,大就在 \(mid\) 的左边找,小就在 \(mid\) 的右边找。

例题代码(P1873):

#include <iostream>

#define ll long long

using namespace std;
int n,m;
ll h[10000001];

bool cmp(ll height) {
    ll tot=0;
    for (int i=1;i<=n;i++) {
        if (h[i]>=height) {
            tot+=h[i]-height;
        }
    }
    return tot>=m;
}

int main() {
    cin>>n>>m;
    for (int i=1;i<=n;i++) {
        cin>>h[i];
    }
    ll l=1,r=1e9,mid=0,ans=0;
    while (l<=r) {
        if (cmp(mid=l+r>>1)) {
            ans=mid;
            l=mid+1;
        } else {
            r=mid-1;
        }
    }
    cout<<ans;
}

STL

STL 大法好!!

在 STL 中也有二分函数,分别为 upper_houndlower_hound

upper_hound 是查找首个大于给定元素的元素地址,lower_hound 是查找首个不小于给定元素的元素地址(记得是地址,所以一般用的时候要减去数组首地址)。

例题代码(P1020

#include <algorithm>
#include <iostream>

using namespace std;
int n,cnt=1,cnt1=1;
int h[100001];
int f[100001],s[100001];

bool cmp(int a,int b) {
    return a>b;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
#endif
    n=1;
    while (cin>>h[n]) {
        n++;
    }
    n--;
    f[1]=s[1]=h[1];
    for (int i=2;i<=n;i++) {
        if (f[cnt]>=h[i]) {
            f[++cnt]=h[i];
        } else {
            f[upper_bound(f+1,f+cnt+1,h[i],cmp)-f]=h[i];
        }
        if (s[cnt1]<h[i]) {
            s[++cnt1]=h[i];
        } else {
            s[lower_bound(s+1,s+cnt1+1,h[i])-s]=h[i];
        }
    }
    cout<<cnt<<endl<<cnt1;
    return 0;
}

finally

没了。