算法常用模板

一、数论

1.试除法判定质数

cpp 复制代码
#include<iostream>
using namespace std;

int ff(int x){
    if(x < 2) return 0;
    for(int i = 2; i <= x / i; i++){
        if(x % i == 0) return 0;
    }
    return 1;
}

int main(){
    int t;
    cin>>t;
    int x;
    while(t--){
        cin>>x;
        int y = ff(x);
        if(y) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

2.分解质因数

cpp 复制代码
#include<iostream>
using namespace std;

void ff(int x){
    for(int i = 2; i <= x / i; i++){
        if(x % i == 0){
            int cnt = 0;
            while(x % i == 0){
                cnt++;
                x /= i;
            }
            cout<<i<<" "<<cnt<<endl;
        }
    }
    if(x > 1) cout<<x<<" "<<1<<endl;
}

int main(){
    int n;
    cin>>n;
    int x;
    while(n--){
        cin>>x;
        ff(x);
        cout<<endl;
    }
    return 0;
}

3.筛质数

cpp 复制代码
// 埃氏筛法
#include<iostream>
using namespace std;
const int N = 1e6;
int prim[N], vis[N];

void ff(int n){
    int cnt = 0;
    for(int i = 2; i <= n; i++){
        if(!vis[i]){
            vis[i] = 1;
            prim[++cnt] = i;
            for(int j = i + i; j <= n; j += i) vis[j] = 1;
        }
    }
    for(int i = 1; i <= cnt; i++) cout<<prim[i]<<" ";
    cout<<endl;
    cout<<cnt;
}

int main(){
    int n;
    cin>>n;
    ff(n);
    return 0;
}

// 线性筛法
#include<iostream>
using namespace std;
const int N = 1e6;
int prim[N], vis[N];

void ff(int n){
    int cnt = 0;
    for(int i = 2; i <= n; i++){
        if(!vis[i]){
            vis[i] = 1;
            prim[++cnt] = i;
        }
        for(int j = 1; prim[j] <= n / i; j++){
            // 用最小质因子筛合数
            vis[i * prim[j]] = 1;
            if(i % prim[j] == 0) break;
        }
    }
    //for(int i = 1; i <= cnt; i++) cout<<prim[i]<<" ";
    //cout<<endl;
    cout<<cnt;
}

int main(){
    int n;
    cin>>n;
    ff(n);
    return 0;
}

4.试除法求约数

cpp 复制代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

void ff(int x){
    int cnt = 0;
    vector<int> v;
    for(int i = 1; i <= x / i; i++){
        if(x % i == 0){
            v.push_back(i);
            if(x / i != i) v.push_back(x / i);
        }
    }
    sort(v.begin(), v.end());
    for(int i : v) cout<<i<<" ";
}

int main(){
    int n;
    cin>>n;
    int x;
    while(n--){
        cin>>x;
        ff(x);
        cout<<endl;
    }
    return 0;
}

5.约数个数

cpp 复制代码
#include<iostream>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
map<int, int> mp;

void ff(int x){
    for(int i = 2; i <= x / i; i++){
        while(x % i == 0){
            mp[i]++;
            x /= i;
        }
    }
    if(x > 1) mp[x]++;
}

int main(){
    int n;
    cin>>n;
    int x;
    while(n--){
        cin>>x;
        ff(x);
    }
    long long ans = 1;
    for(auto i : mp){
        ans = ans * (i.second + 1) % mod;
    }
    cout<<ans;
    return 0;
}

6.约数之和

cpp 复制代码
#include<iostream>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
map<int, int> mp;

void ff(int x){
    for(int i = 2; i <= x / i; i++){
        while(x % i == 0){
            mp[i]++;
            x /= i;
        }
    }
    if(x > 1) mp[x]++;
}

int main(){
    int n;
    cin>>n;
    int x;
    while(n--){
        cin>>x;
        ff(x);
    }
    long long ans = 1;
    for(auto i : mp){
        long long res = 1;
        int a = i.first, b = i.second;
        while(b--){
            res = (res * a + 1) % mod;
        }
        ans = (ans * res) % mod;
    }
    cout<<ans;
    return 0;
}

7.最大公约数

cpp 复制代码
#include<iostream>
using namespace std;

int gcd(int a, int b){
    if(b == 0) return a;
    else return gcd(b, a % b);
}

int main(){
    int n;
    cin>>n;
    int a, b;
    while(n--){
        cin>>a>>b;
        int res = gcd(a, b);
        cout<<res<<endl;
    }
    return 0;
}

8.最小公倍数

cpp 复制代码
#include<iostream>
using namespace std;

int gcd(int a, int b){
    if(b == 0) return a;
    else return gcd(b, a % b);
}

int main(){
    int n;
    cin>>n;
    int a, b;
    while(n--){
        cin>>a>>b;
        int res = a * b / gcd(a, b);
        cout<<res<<endl;
    }
    return 0;
}

9.欧拉函数

cpp 复制代码
#include<iostream>
using namespace std;

void ff(int x){
    int res = x;
    for(int i = 2; i <= x / i; i++){
        if(x % i == 0){
            while(x % i == 0){
                x /= i;
            }
            res = res / i * (i - 1);
        }
    }
    if(x > 1) res = res / x * (x - 1);
    cout<<res<<endl;
}

int main(){
    int n;
    cin>>n;
    int x;
    while(n--){
        cin>>x;
        ff(x);
    }
    return 0;
}

10.快速幂

cpp 复制代码
#include<iostream>
using namespace std;

void ff(int a, int b, int p){
    int res = 1 % p;
    while(b){
        if(b & 1) res = 1ll * res * a % p;
        a = 1ll * a * a % p;
        b >>= 1;
    }
    cout<<res<<endl;
}

int main(){
    int n;
    cin>>n;
    int a, b, p;
    while(n--){
        cin>>a>>b>>p;
        ff(a, b, p);
    }
    return 0;
}

11.快速幂求逆元

a / b ≡ a * x (mod n)

两边同乘b可得 a ≡ a * b * x (mod n)

即 1 ≡ b * x (mod n)

同 b * x ≡ 1 (mod n)

由费马小定理可知,当n为质数时

b ^ (n - 1) ≡ 1 (mod n)

拆一个b出来可得 b * b ^ (n - 2) ≡ 1 (mod n)

故当n为质数时,b的乘法逆元 x = b ^ (n - 2)

cpp 复制代码
#include<iostream>
using namespace std;

int ff(int a, int b, int p){
    int res = 1 % p;
    while(b){
        if(b & 1) res = 1ll * res * a % p;
        a = 1ll * a * a % p;
        b >>= 1;
    }
    return res;
}

int main(){
    int n;
    cin>>n;
    int a, p;
    while(n--){
        cin>>a>>p;
        int res = ff(a, p - 2, p);
        if(a % p) cout<<res<<endl;
        else cout<<"impossible"<<endl;
    }
    return 0;
}

12.扩展欧几里得

裴蜀定理:有一对正整数 a,b,那么一定存在非零 x,y,使得 ax + by = gcd(a, b)

即 a 和 b 的最大公因数是 a 和 b 能凑出来的最小正整数

cpp 复制代码
#include<iostream>
using namespace std;

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main(){
    int n;
    cin>>n;
    int a, b;
    while(n--){
        cin>>a>>b;
        int x, y;
        int res = exgcd(a, b, x, y);
        //cout<<res<<endl;
        cout<<x<<" "<<y<<endl;
    }
    return 0;
}

13.扩展欧几里得求逆元

a有逆元的充要条件是a与p互质,所以gcd(a, p) = 1

假设a的逆元为x,那么有a * x ≡ 1 (mod p)

等价:ax + py = 1

exgcd(a, p, x, y)

cpp 复制代码
#include<iostream>
using namespace std;

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main(){
    int n;
    cin>>n;
    int a, p;
    while(n--){
        cin>>a>>p;
        int x, y;
        int d = exgcd(a, p, x, y);
        if(d == 1) cout<<(1ll * x + p) % p<<endl;
        else cout<<"impossible"<<endl;
    }
    return 0;
}

14.求组合数

cpp 复制代码
// 在 2000 范围内
#include<iostream>
using namespace std;
const int N = 2e3 + 10, mod = 1e9 + 7;
int f[N][N];

void init(){
    f[0][0] = f[1][0] = f[1][1] = 1;
    for(int i = 2; i < N; i++){
        for(int j = 0; j <= i; j++){
            if(!j) f[i][j] = 1;
            else f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % mod;
        }
    }
}

int main(){
    init();
    int n;
    cin>>n;
    int a, b;
    while(n--){
        cin>>a>>b;
        cout<<f[a][b]<<endl;
    }
    return 0;
}

// 在 100000 范围内
#include<iostream>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
int fact[N], infact[N];

int qm(int a, int b, int p){
    int res = 1 % p;
    while(b){
        if(b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

void init(){
    fact[0] = infact[0] = 1;
    for(int i = 1; i < N; i++){
        fact[i] = 1ll * fact[i - 1] * i % mod;
        infact[i] = 1ll* infact[i - 1] * qm(i, mod - 2, mod) % mod;
    }
}

int main(){
    init();
    int n;
    cin>>n;
    int a, b;
    while(n--){
        cin>>a>>b;
        int res = 1ll * fact[a] * infact[a - b] % mod * infact[b] % mod;
        cout<<res<<endl;
    }
    return 0;
}

二、图论

1.拓扑序列

cpp 复制代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<int> g[N];
int ru[N], a[N];
int n, m;

void ff(){
    queue<int> q;
    for(int i = 1; i <= n; i++){
        if(!ru[i]){
            q.push(i);
        }
    }
    int siz = 0;
    while(q.size()){
        int x = q.front();
        q.pop();
        a[++siz] = x;
        for(int y : g[x]){
            if(ru[y]){
                ru[y]--;
                if(!ru[y]){
                    q.push(y);
                }
            }
        }
    }
    if(siz != n) cout<<-1;
    else{
        for(int i = 1; i <= siz; i++){
            cout<<a[i]<<" ";
        }
    }
}

int main(){
    cin>>n>>m;
    int x, y;
    for(int i = 1; i <= m; i++){
        cin>>x>>y;
        g[x].push_back(y);
        ru[y]++;
    }
    ff();
    return 0;
}

2.dijkstra

cpp 复制代码
// O(n ^ 2)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 510;
vector<pair<int, int>> g[N];
int vis[N], dis[N];
int n, m;

void ff(int st, int ed){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    while(1){
        int x = -1;
        for(int i = 1; i <= n; i++){
            if(!vis[i] && dis[i] < 0x3f3f3f3f && (x == -1 || dis[x] > dis[i])){
                x = i;
            }
        }
        if(x == -1 || x == ed) break;
        vis[x] = 1;
        for(auto i : g[x]){
            int y = i.first, z = i.second;
            if(dis[x] + z < dis[y]){
                dis[y] = dis[x] + z;
            }
        }
    }
    if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
    else cout<<-1;
}

int main(){
    cin>>n>>m;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        // 判重,取边权小的
        int ok = 0;
        for(auto& j : g[x]){
            if(j.first == y){
                if(j.second > z){
                    j.second = z;
                }
                ok = 1;
                break;
            }
        }
        if(!ok) g[x].push_back({y, z});
    }
    ff(1, n);
    return 0;
}

// O((n + m)logn)
```cpp
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
const int N = 2e5 + 10;
vector<pair<int, int>> g[N];
set<pair<int, int>> q;
int dis[N];
int n, m;

void ff(int st, int ed){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    for(int i = 1; i <= n; i++){
        q.insert({dis[i], i});
    }
    while(q.size()){
        auto x = q.begin() -> second;
        q.erase(q.begin());
        if(x == ed || dis[x] > 0x3f3f3f3f) break;
        for(auto i : g[x]){
            int y = i.first, z = i.second;
            if(dis[x] + z < dis[y]){
                q.erase({dis[y], y});
                dis[y] = dis[x] + z;
                q.insert({dis[y], y});
            }
        }
    }
    if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
    else cout<<-1;
}

int main(){
    cin>>n>>m;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        int ok = 0;
        // for(auto& j : g[x]){
        //     if(j.first == y){
        //         if(j.second > z){
        //             j.second = z;
        //         }
        //         ok = 1;
        //         break;
        //     }
        // }
        if(!ok) g[x].push_back({y, z});
    }
    ff(1, n);
    return 0;
}

3.bellman

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
struct Point{
    int x, y, z;
}g[N];
int dis[N], b[N], pre[N];
int n, m, k;

void ff(int st, int ed){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    int cnt = 0;
    while(1){
        cnt++;
        int ok = 0;
        // 每次只能用之前的状态更新
        memcpy(b, dis, sizeof(dis));
        for(int i = 1; i <= m; i++){
            int x = g[i].x, y = g[i].y, z = g[i].z;
            if(dis[x] < 0x3f3f3f3f && b[x] + z < dis[y]){
                dis[y] = b[x] + z;
                pre[y] = x;
                ok = 1;
            }
        }
        if(!ok || cnt >= k) break;
    }
    if(dis[ed] < 0x3f3f3f3f){
        // for(int i = ed; i != st; i = pre[i]){
        //     cout<<i<<" ";
        // }
        // cout<<st<<endl;
        cout<<dis[ed];
    }
    else cout<<"impossible";
}

int main(){
    cin>>n>>m>>k;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        g[i] = {x, y, z};
    }
    ff(1, n);
    return 0;
}

4.spfa

cpp 复制代码
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int>> g[N];
queue<int> q;
int dis[N], vis[N], pre[N];
int n, m;

void ff(int st, int ed){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    vis[st] = 1;
    q.push(st);
    while(q.size()){
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for(auto i : g[x]){
            int y = i.first, z = i.second;
            if(dis[x] < 0x3f3f3f3f && dis[x] + z < dis[y]){
                dis[y] = dis[x] + z;
                pre[y] = x;
                if(!vis[y]){
                    q.push(y);
                    vis[y] = 1;
                }
            }
        }
    }
    if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
    else cout<<"impossible";
}

int main(){
    cin>>n>>m;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        g[x].push_back({y, z});
    }
    ff(1, n);
    return 0;
}

// 判负环,如果最短路径边数大于等于 n,那就有负环
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int>> g[N];
queue<int> q;
int dis[N], vis[N], pre[N], cnt[N];
int n, m;

void ff(){
    //memset(dis, 0x7f, sizeof(dis));
    for(int i = 1; i <= n; i++){
        q.push(i);
        vis[i] = 1;
    }
    int ok = 0;
    while(q.size()){
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for(auto i : g[x]){
            int y = i.first, z = i.second;
            if(dis[x] < 0x3f3f3f3f && dis[x] + z < dis[y]){
                dis[y] = dis[x] + z;
                cnt[y] = cnt[x] + 1;
                if(cnt[y] >= n){
                    ok = 1;
                    break;
                }
                pre[y] = x;
                if(!vis[y]){
                    q.push(y);
                    vis[y] = 1;
                }
            }
        }
        if(ok) break;
    }
    if(ok) cout<<"Yes";
    else cout<<"No";
}

int main(){
    cin>>n>>m;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        g[x].push_back({y, z});
    }
    ff();
    return 0;
}

5.floyd

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210;
int f[N][N], dis[N][N];
int n, m, q;

int main(){
    cin>>n>>m>>q;
    int x, y, z;
    memset(dis, 0x7f, sizeof(dis));
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        dis[x][y] = min(dis[x][y], z);
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i == j) f[i][j] = 0;
            else f[i][j] = dis[i][j];
        }
    }
    for(int k = 1; k <= n; k++){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(f[i][k] < 0x3f3f3f3f && f[k][j] < 0x3f3f3f3f){
                    f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
                }
            }
        }
    }
    while(q--){
        cin>>x>>y;
        if(f[x][y] < 0x3f3f3f3f) cout<<f[x][y]<<endl;
        else cout<<"impossible"<<endl;
    }
    return 0;
}

6.prim

cpp 复制代码
// O(n ^ 2)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 550;
vector<pair<int, int>> g[N];
int vis[N], dis[N];
int n, m;

int test(int st){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    int ans = 0, cnt = 0;
    while(1){
        int x = -1;
        for(int i = 1; i <= n; i++){
            if(!vis[i] && dis[i] < 0x3f3f3f3f && (x == -1 || dis[i] < dis[x])){
                x = i;
            }
        }
        if(x == -1) break;
        vis[x] = 1;
        cnt++;
        ans += dis[x];
        for(auto i : g[x]){
            int y = i.first, w = i.second;
            dis[y] = min(dis[y], w);
        }
    }
    if(cnt != n) return 1e9;
    else return ans;
}

int main(){
    scanf("%d%d", &n, &m);
    int x, y, w;
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d", &x, &y, &w);
        g[x].push_back({y, w});
        g[y].push_back({x, w});
    }
    int res = test(1);
    if(res != 1e9) printf("%d", res);
    else printf("impossible");
    return 0;
}


// O((n + m)logn)
#include<iostream>
#include<set>
#include<vector>
#include<cstring>
using namespace std;
const int N = 550;
set<pair<int, int>> q;
vector<pair<int, int>> g[N];
int dis[N], vis[N];
int n, m;

int test(int st){
    memset(dis, 0x7f, sizeof(dis));
    dis[st] = 0;
    for(int i = 1; i <= n; i++){
        q.insert({dis[i], i});
    }
    int ans = 0, cnt = 0;
    while(q.size()){
        int x = q.begin() -> second;
        q.erase(q.begin());
        vis[x] = 1;
        if(dis[x] > 0x3f3f3f3f) break;
        ans += dis[x];
        cnt++;
        for(auto i : g[x]){
            int y = i.first, w = i.second;
            if(!vis[y] && w < dis[y]){
                q.erase({dis[y], y});
                dis[y] = w;
                q.insert({dis[y], y});
            }
        }
    }
    if(cnt != n) return 1e9;
    else return ans;
}

int main(){
    scanf("%d%d", &n, &m);
    int x, y, w;
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d", &x, &y, &w);
        g[x].push_back({y, w});
        g[y].push_back({x, w});
    }
    int res = test(1);
    if(res == 1e9) printf("impossible");
    else printf("%d", res);
    return 0;
}

7.kruskal

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
struct Point{
    int x, y, z;
    bool operator<(const Point& p)const{
        return z < p.z;
    }
}g[N];
int p[N];
int n, m;
int cnt;

int fd(int x){
    if(x != p[x]){
        p[x] = fd(p[x]);
    }
    return p[x];
}

void ff(){
    for(int i = 1; i <= n; i++){
        p[i] = i;
    }
    sort(g + 1, g + cnt + 1);
    int ans = 0, res = 0;
    for(int i = 1; i <= cnt; i++){
        int x = g[i].x, y = g[i].y, z = g[i].z;
        int xx = fd(x), yy = fd(y);
        if(xx != yy){
            p[yy] = xx;
            ans += z;
            res++;
        }
        //if(res == n - 1) break;
    }
    if(res < n - 1) cout<<"impossible";
    else cout<<ans;
}

int main(){
    cin>>n>>m;
    int x, y, z;
    for(int i = 1; i <= m; i++){
        cin>>x>>y>>z;
        g[++cnt] = {x, y, z};
        //g[++cnt] = {y, x, z};
    }
    ff();
    return 0;
}

三、贪心

1.区间选点

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> a;
int n, cnt;

bool cmp(const pair<int, int> &p, const pair<int, int> &q){
    return p.second < q.second;
}

int main(){
    cin>>n;
    while(n--){
        int l, r;
        cin>>l>>r;
        a.push_back({l, r});
    }
    sort(a.begin(), a.end(), cmp);
    int ed = -2e9;
    for(auto it : a){
        if(ed < it.first){
            cnt++;
            ed = it.second;
        }
    }
    cout<<cnt;
    return 0;
}

2.最大不相交区间数量

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> a;
int n, cnt;

bool cmp(const pair<int, int> &p, const pair<int, int> &q){
    return p.second < q.second;
}

int main(){
    cin>>n;
    while(n--){
        int l, r;
        cin>>l>>r;
        a.push_back({l, r});
    }
    sort(a.begin(), a.end(), cmp);
    int ed = -2e9;
    for(auto it : a){
        if(ed < it.first){
            cnt++;
            ed = it.second;
        }
    }
    cout<<cnt;
    return 0;
}

3.区间分组

cpp 复制代码
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
vector<pair<int, int>> a;
int n;

bool cmp(const pair<int, int> &x, const pair<int, int> &y){
    return x.first < y.first;
}

int main(){
    cin>>n;
    for(int i = 0; i < n; i++){
        int l, r;
        cin>>l>>r;
        a.push_back({l, r});
    }
    sort(a.begin(), a.end(), cmp);
    priority_queue<int, vector<int>, greater<int>> h;
    int m = a.size();
    for(int i = 0; i < m; i++){
        if(h.empty() || h.top() >= a[i].first) h.push(a[i].second);
        else{
            h.pop();
            h.push(a[i].second);
        }
    }
    cout<<h.size(); //h.size()是size_t类型,无符号整数
    return 0;
}

4.区间覆盖

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int st, ed;
int res;
int n;
int f;
vector<pair<int, int>> a;

int main(){
    cin>>st>>ed;
    cin>>n;
    for(int i = 0; i < n; i++){
        int l, r;
        cin>>l>>r;
        a.push_back({l, r});
    }
    sort(a.begin(), a.end());
    for(int i = 0; i < n; i++){
        int j = i, r = -2e9;
        while(j < n && a[j].first <= st){
            r = max(r, a[j].second);
            j++;
        }
        if(r < st) break;
        res++;
        if(r >= ed){
            f = 1;
            break;
        }
        st = r;
        i = j - 1;
    }
    if(f == 1) cout<<res;
    else cout<<-1;
    return 0;
}

四、数据结构

1.kmp

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
char s[N], p[N];
int ne[N], f[N];
int n, m;

void ff(){
    ne[1] = 0;
    int j = 0;
    for(int i = 2; i <= m; i++){
        while(j > 0 && p[i] != p[j + 1]) j = ne[j];
        if(p[i] == p[j + 1]) j++;
        ne[i] = j;
    }
    j = 0;
    for(int i = 1; i <= n; i++){
        while(j > 0 && s[i] != p[j + 1]) j = ne[j];
        if(s[i] == p[j + 1]) j++;
        f[i] = j;
    }
    for(int i = 1; i <= n; i++){
        if(f[i] == m){
            cout<<(i - m)<<" ";
        }
    }
}

int main(){
    cin>>m;
    cin>>(p + 1);
    cin>>n;
    cin>>(s + 1);
    ff();
    return 0;
}

2.z函数

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 2e6 + 10;
char s[N], p[N];
int z[N];
int n, m;

void ff(){
    p[m + 1] = '#';
    for(int i = m + 2, j = 1; j <= n; i++, j++){
        p[i] = s[j];
    }
    z[1] = 0;
    int L = 1, R = 0;
    for(int i = 2; i <= n + m + 1; i++){
        if(i > R){
            z[i] = 0;
        }else{
            int k = i - L + 1;
            z[i] = min(z[k], R - i + 1);
        }
        while(z[i] + i <= n + m + 1 && p[z[i] + 1] == p[z[i] + i]){
            z[i]++;
        }
        if(z[i] + i - 1 > R){
            L = i, R = z[i] + i - 1;
        }
    }
    for(int i = m + 2; i <= n + m + 1; i++){
        if(z[i] == m){
            cout<<(i - m - 2)<<" ";
        }
    }
}

int main(){
    cin>>m;
    cin>>(p + 1);
    cin>>n;
    cin>>(s + 1);
    ff();
    return 0;
}

3.trie树

cpp 复制代码
// 字符统计
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int son[N][26], cnt[N], idx;
int n;

void insert(string s){
    // 0是根节点
    int p = 0;
    for(int i = 0; i < s.size(); i++){
        int u = s[i] - 'a';
        if(!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
    cnt[p]++;
}

int query(string s){
    int p = 0;
    for(int i = 0; i < s.size(); i++){
        int u = s[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int main(){
    cin>>n;
    char c;
    string s;
    while(n--){
        cin>>c;
        if(c == 'I'){
            cin>>s;
            insert(s);
        }else{
            cin>>s;
            cout<<query(s)<<endl;
        }
    }
    return 0;
}

// 求数组两个数最大异或
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int son[31 * N][2], idx;
int n;

void insert(int x){
    int p = 0;
    for(int i = 30; i >= 0; i--){
        int u = x >> i & 1;
        if(!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
}

int query(int x){
    int p = 0, sum = 0;
    for(int i = 30; i >= 0; i--){
        int u = x >> i & 1;
        if(son[p][!u]){
            p = son[p][!u];
            sum = 2 * sum + 1;
        }else{
            p = son[p][u];
            sum = 2 * sum + 0;
        }
    }
    return sum;
}

int main(){
    cin>>n;
    int x, res;
    while(n--){
        cin>>x;
        insert(x);
        res = max(res, query(x));
    }
    cout<<res;
    return 0;
}

4.并查集

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int n, m;

int find(int x){
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}

int main(){
    cin>>n>>m;
    for(int i = 1; i <= n; i++) p[i] = i;
    char c;
    int a, b;
    while(m--){
        cin>>c;
        cin>>a>>b;
        if(c == 'M'){
            if(find(a) == find(b)) continue;
            p[find(a)] = find(b);
        }else{
            cout<<(find(a) == find(b) ? "Yes" : "No")<<endl;
        }
    }
    return 0;
}

五、基础算法

快速排序

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], n;

void q(int a[], int l, int r){
    if(l >= r) return;
    int mid = a[(l + r + 1) / 2], i = l - 1, j = r + 1;
    while(i < j){
        do i++; while(a[i] < mid);
        do j--; while(a[j] > mid);
        if(i < j) swap(a[i], a[j]);
    }
    q(a, l, i - 1);
    q(a, i, r);
}

int main(){
    cin>>n;
    for(int i = 1; i <= n; i++) cin>>a[i];
    q(a, 1, n);
    for(int i = 1; i <= n; i++) cout<<a[i]<<" ";
    return 0;
}

归并排序

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], b[N], n;

void q(int a[], int l, int r){
    if(l >= r) return;
    int mid = (l + r) / 2;
    q(a, l, mid), q(a, mid + 1, r);
    int x = 1, i = l, j = mid + 1;
    while(i <= mid && j <= r){
        if(a[i] <= a[j]) b[x++] = a[i++];
        else b[x++] = a[j++];
    }
    while(i <= mid) b[x++] = a[i++];
    while(j <= r) b[x++] = a[j++];
    for(int i = l, j = 1; i <= r; i++, j++) a[i] = b[j];
}

int main(){
    cin>>n;
    for(int i = 1; i <= n; i++) cin>>a[i];
    q(a, 1, n);
    for(int i = 1; i <= n; i++) cout<<a[i]<<" ";
    return 0;
}

六、动态规划

1.01背包

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;
int v, w;

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++){
        scanf("%d%d", &v, &w);
        for(int j = m; j >= v; j--){
            f[j] = max(f[j], f[j - v] + w);
        }
    }
    printf("%d", f[m]);
    return 0;
}

2.完全背包

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;

int main(){
    scanf("%d%d", &n, &m);
    int v, w;
    for(int i = 0; i < n; i++){
        scanf("%d%d", &v,&w);
        for(int j = v; j <= m; j++){
            f[j] = max(f[j], f[j - v] + w);
        }
    }
    printf("%d", f[m]);
    return 0;
}

3.多重背包

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e4 + 10;
int f[N];
int n, m;
struct Point{
	int v, w;
};

int main(){
	int hh1, mm1, hh2, mm2;
	scanf("%d:%d %d:%d %d", &hh1, &mm1, &hh2, &mm2, &n);
	m = hh2 * 60 + mm2 - (hh1 * 60 + mm1);
	int v, w, s;
	vector<Point> a;
	for(int i = 1; i <= n; i++){
		cin>>v>>w>>s;
		if(s == 0){
			s = 1000;
		}
		for(int j = 1; j <= s; j *= 2){
			a.push_back({j * v, j * w});
			s -= j;
		}
		if(s > 0){
			a.push_back({s * v, s * w});
		}
	}
	for(int i = 0; i < a.size(); i++){
		for(int j = m; j >= a[i].v; j--){
			f[j] = max(f[j], f[j - a[i].v] + a[i].w);
		}
	}
	cout<<f[m];
	return 0;
}

4.混合背包

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
const int N = 1010;
int f[N];
int n, m;

struct Good{
    int id;
    int v, w;
};

int main(){
    scanf("%d%d", &n, &m);
    vector<Good> goods;
    int v, w, s;
    for(int i = 0; i < n; i++){
        scanf("%d%d%d", &v, &w, &s);
        if(s == -1) goods.push_back({-1, v, w});
        else if(s == 0) goods.push_back({0, v, w});
        else{
            for(int j = 1; j <= s; j *= 2){
                s -= j;
                goods.push_back({-1, j * v, j * w});
            }
            if(s > 0) goods.push_back({-1, s * v, s * w});
        }
    }
    for(auto good : goods){
        if(good.id == -1){
            for(int j = m; j >= good.v; j--){
                f[j] = max(f[j], f[j - good.v] + good.w);
            }
        }else{
            for(int j = good.v; j <= m; j++){
                f[j] = max(f[j], f[j - good.v] + good.w);
            }
        }
    }
    printf("%d", f[m]);
    return 0;
}

5.分组背包

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N];
int v[N], w[N];
int b[N], g[110][110];
int n, m;

int main(){
	cin>>m>>n;
	int x, t = 0;
	for(int i = 1; i <= n; i++){
		cin>>v[i]>>w[i]>>x;
		t = max(t, x);
		// 小组 x 的物品个数加一 
		b[x]++; 
		// 小组 i 中第 j 个物品的编号
		g[x][b[x]] = i; 
	}
	for(int i = 1; i <= t; i++){
		for(int j = m; j >= 0; j--){
			for(int z = 1; z <= b[i]; z++){
				if(j >= v[g[i][z]]){
					f[j] = max(f[j], f[j - v[g[i][z]]] + w[g[i][z]]);
				} 
			}
		}
	}
	cout<<f[m];
	return 0;
}

6.背包问题求具体方案数

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N], sum[N];
int n, m;
int v, w;

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 0; i <= m; i++) sum[i] = 1;
    for(int i = 0; i < n; i++){
        scanf("%d%d", &v, &w);
        for(int j = m; j >= v; j--){
            int t = f[j - v] + w;
            if(t > f[j]){
                f[j] = t;
                sum[j] = sum[j - v];
            }
            else if(t == f[j]) sum[j] = (sum[j] + sum[j - v]) % mod;
        }
    }
    printf("%d", sum[m]);
    return 0;
}

7.背包问题求具体方案

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1010;
int f[N][N], v[N], w[N];
int sp[N];
int n, m;

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]);
    for(int i = n; i >= 1; i--){
        for(int j = 0; j <= m; j++){
            f[i][j] = f[i + 1][j];
            if(j >= v[i]){
                f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
            }
        }
    }
    int cnt = 0;
    for(int i = 1, j = m; i <= n; i++){
        if(j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]){
            sp[++cnt] = i;
            j -= v[i];
        }
    }
    for(int i = 1; i <= cnt; i++) printf("%d ", sp[i]);
    return 0;
}
相关推荐
小鱼仙官22 分钟前
MFC中Picture Control控件显示照片的几种方式
c++·mfc
薯条不要番茄酱23 分钟前
数据结构-5.二叉树
java·开发语言·数据结构
cleverpeople1 小时前
11.15作业
c语言·开发语言·算法
Seeklike1 小时前
11.14 机器学习-朴素贝叶斯+决策树算法
算法·决策树·机器学习
徐浪老师3 小时前
深入解析贪心算法及其应用实例
算法·贪心算法
软行3 小时前
LeetCode 单调栈 下一个更大元素 I
c语言·数据结构·算法·leetcode
钰爱&4 小时前
【操作系统】Linux之线程同步二(头歌作业)
linux·运维·算法
Ws_4 小时前
leetcode LCR 068 搜索插入位置
数据结构·python·算法·leetcode
灼华十一4 小时前
数据结构-布隆过滤器和可逆布隆过滤器
数据结构·算法·golang
adam_life6 小时前
OpenJudge_ 简单英文题_04:0/1 Knapsack
算法·动态规划