算法基础模板整理(基础知识篇)

发布时间 2023-04-14 00:51:39作者: Amαdeus

排序

快速排序 线性时间选择

int partition(int l, int r){
    int pos = rand() % (r - l + 1) + l;
    swap(a[pos], a[l]);

    int key = a[l], i = l, j = r;
    while(i != j){
        while(i < j && a[j] >= key) j -- ;
        while(i < j && a[i] <= key) i ++ ;
        swap(a[i], a[j]);
    }
    swap(a[i], a[l]);
    return i;
}

int select(int l, int r, int k){
    if(l == r) return a[l];
    int mid = partition(l, r);
    int res = mid - l + 1;    //res表示当前是范围内的第几小
    if(k == res) return a[mid];
    if(k < res)  return select(l, mid - 1, k);
    else  return select(mid + 1, r, k - res);
}

归并排序 归并排序求逆序对

void merge(int l, int mid, int r){
    int tmp[r - l + 1];
    int i = l, j = mid + 1, k = 0;

    while(i <= mid && j <= r){
        if(a[i] <= a[j]) tmp[k ++ ] = a[i ++ ];
        else tmp[k ++ ] = a[j ++ ], res += mid - i + 1;
    }

    while(i <= mid) tmp[k ++ ] = a[i ++ ];
    while(j <= r) tmp[k ++ ] = a[j ++ ];

    for(int idx = l, kk = 0; idx <= r; idx ++ , kk ++ )
        a[idx] = tmp[kk];
}

void mergesort(int l, int r){
    if(l >= r) return;
    int mid = l + r >> 1;
    mergesort(l, mid);
    mergesort(mid + 1, r);
    merge(l, mid, r);
}


二分查找

int binaryfirst(int a[], int x){
    int l = 0, r = n - 1;
    while(l < r){
        int mid = l + r >> 1;
        if(a[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return a[r] == x ? r : -1;
}

int binarylast(int a[], int x){
    int l = 0, r = n - 1;
    while(l < r){
        int mid = l + r + 1 >> 1;
        if(a[mid] <= x) l = mid;
        else r = mid - 1;
    }
    return a[r] == x ? r : -1;
}


高精度

高精度加法

vector<int> add(vector<int> &A, vector<int> &B){
    vector<int> C;
    int m = A.size(), n = B.size();
    int cur = 0, i = 0;
    
    while(i < m || i < n){
        if(i < m) cur += A[i];
        if(i < n) cur += B[i];
        C.push_back(cur % 10);
        cur /= 10;
        i ++ ;
    }
    
    if(cur) C.push_back(1);
    return C;
}

int main(){
    string a, b; cin >> a >> b;
    vector<int> A, B;
    for(int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for(int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
    
    vector<int> C = add(A, B);
    
    for(int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    
    return 0;
}

高精度减法

bool cmp(vector<int>& A, vector<int> &B){
    if(A.size() != B.size()) return A.size() > B.size(); 
    for(int i = A.size(); i >= 0; i--)
        if(A[i] != B[i]) return A[i] > B[i];
    return true;
}

vector<int> sub(vector<int>& A, vector<int> &B){
    vector<int> C;
    int t = 0;
    for(int i = 0; i < A.size(); i++){
        t = A[i] - t;
        if(i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10); 
        if(t < 0)  t = 1;
        else t = 0;
    }
    while(C.size() > 1 && C.back() == 0) C.pop_back();  //去掉前导0

    return C;
}

int main(){ 
    string a, b;  cin >> a >> b;
    vector<int> A, B;
    for(int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for(int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');

    if(cmp(A, B)){
        auto C = sub(A, B);
        for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
    }else{
        auto C = sub(B, A);
        printf("-");
        for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
    }
    return 0;
}

高精度乘法

vector<int> mul(vector <int> & A, int b) {
    vector<int> C;
    int t = 0;
    for(int i = 0; i < A.size(); i ++ ){
        t += A[i] * b;       
        C.push_back(t % 10); 
        t /= 10;            
    }

    while(t){            
        C.push_back(t % 10);
        t /= 10;
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;
}

高精度除法

vector<int> div(vector<int> &A, int b, int &r){
    vector<int> C;
    for(int i = 0; i < A.size(); i ++ ){
        r = r * 10 + A[i];
        C.push_back(r / b);
        r = r % b;
    }
    reverse(C.begin(), C.end());
    while(C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}


前缀和

一维前缀和

static const int N = 1e5 + 10;
int a[N], s[N], n, q;

int main(){
    cin >> n >> q;
    for(int i = 1; i <= n; i ++ ){
        cin >> a[i];
        s[i] = s[i - 1] + a[i];
    }
    
    while(q -- ){
        int l, r; cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;
    }
    
    return 0;
}

二维前缀和

static const int N = 1010;
int s[N][N], n, m, q;

int main(){
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            int x; cin >> x;
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + x;
        }
        
    while(q -- ){
        int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
    }
    
    return 0;
}


差分

一维差分

static const int N = 1e5 + 10;
int b[N];

int main(){
    int n, m; cin >> n >> m;
    for(int i = 1; i <= n; i ++ ){
        int x; cin >> x;
        b[i] += x, b[i + 1] -= x;
    }
    
    while(m -- ){
        int l, r, c; cin >> l >> r >> c;
        b[l] += c, b[r + 1] -= c;
    }
    
    for(int i = 1; i <= n; i ++ )
        b[i] += b[i - 1], cout << b[i] << ' ';
}

二维差分

static const int N = 1010;
int b[N][N];

void insert(int x1, int y1, int x2, int y2, int c){
    b[x1][y1] += c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

int main(){
    int n, m, q; cin >> n >> m >> q;
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ ){
            int c; cin >> c;
            insert(i, j, i, j, c);
        }
    
    while(q -- ){
        int x1, y1, x2, y2, c; cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);
    }
    
    for(int i = 1; i <= n; i ++ ){
        for(int j = 1; j <= m; j ++ ){
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
            cout << b[i][j] << ' '; 
        }
        cout << endl;
    }
}


倍增

RMQ 区间最值问题

void rmq(){
    for(int i = 1; i <= n; i ++ ) dp[i][0] = a[i];
    for(int j = 1; j < int(log(n) / log(2)) + 1; j ++ )
        for(int i = 1; i <= n - (1 << j) + 1; i ++ )
           dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
    //分为 [i, i + 2^(j - 1) - 1] 和 [i + 2^(j - 1), i + 2^j - 1] 两个区间的最值的最值
}

while(m -- ){
    int l, r; cin >> l >> r;
    int k = log(r - l + 1) / log(2);
    cout << max(dp[l][k], dp[r - (1 << k) + 1][k]) << endl;
    //以l为开头 [l, l + 2^k - 1] , 以r为结尾 [r - 2^k + 1, r] 
}


区间合并

static const int N = 1e5 + 10;
typedef pair<int, int> pii;
#define l first
#define r second
pii in[N], res[N];
int cnt, n;

int main(){
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> in[i].l >> in[i].r;
    
    sort(in + 1, in + n + 1);
    
    for(int i = 1; i <= n; i ++ )
        if(cnt == 0 || res[cnt].r < in[i].l) res[ ++ cnt] = in[i];
        else res[cnt].r = max(res[cnt].r, in[i].r);
    
    cout << cnt;
    
    return 0;
}


离散化

sort(alls.begin(), alls.end());  //排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); //去重
   
for(auto num : v){ 
    int x = lower_bound(alls.begin(), alls.end(), num) - alls.begin();   
    //二分查找找到x的映射值 
    ...
}