模版代码

\(1600\) 行代码收录着大部分提高级算法.

\(1600\) 行代码埋葬着一位 OIer 的青春.

代码均经 vscode 默认格式化,少量带*的算法为NOI级内容.

也曾想学过太多,但只留下了遗憾与力不从心.

最后修改于 2025.11.28

数据结构

1.ST表

struct SparseTable
{
    int f[T][N];

    void reset(int n, int *a)
    {
        for (int i = 1; i <= n; ++i)
            f[0][i] = a[i];
        for (int i = 1; i < T; ++i)
            for (int j = 1, l = 1 << i; j < l - 1 <= n; ++j)
                f[i][j] = max(f[i - 1][j], f[i - 1][j + (l >> 1)]);
    }
    int query(int l, int r)
    {
        int k = log2(r - l + 1);
        return max(f[k][l], f[k][r - (1 << k) + 1]);
    }
};

2.并查集

  • 普通并查集
struct DisjointSetUnion
{
    int par[N];

    void reset(int n)
    {
        for (int i = 1; i <= n; ++i)
            par[i] = i;
    }
    int find(int u)
    {
        return par[u] == u ? u : par[u] = find(par[u]);
    }
    void merge(int u, int v)
    {
        u = find(u), v = find(v);
        par[u] = v;
    }
};
  • 带权并查集
struct DisjointSetUnion
{
    int par[N], val[N];

    void reset(int n)
    {
        for (int i = 1; i <= n; ++i)
            par[i] = i, val[i] = 0;
    }
    int find(int u)
    {
        if (par[u] == u)
            return u;
        int root = find(par[u]);
        val[u] += val[par[u]];
        return par[u] = root;
    }
    void merge(int u, int v, int w)
    {
        int fu = find(u), fv = find(v);
        par[fu] = fv, val[fu] = w + val[v] - val[u];
    }
};
  • 可撤销并查集
struct DisjointSetUnion
{
    int par[N], siz[N];
    stack<pair<int, int>> his;

    void reset(int n)
    {
        for (int i = 1; i <= n; ++i)
            par[i] = i, siz[i] = 0;
    }
    int find(int u)
    {
        return par[u] == u ? u : find(par[u]);
    }
    void merge(int u, int v)
    {
        u = find(u), v = find(v);
        if(u == v) return;
        if (siz[u] > siz[v])
            swap(u, v);
        his.push({u, siz[u]});
        par[u] = v, siz[v] += siz[u];
    }
    void undo(int tim)
    {
        while (his.size() > tim)
        {
            int u = his.top().first;
            int w = his.top().second;
            his.pop();
            siz[par[u]] -= w, par[u] = u;
        }
    }
};

3.树状数组

  • 普通树状树组
struct BitIndexTree
{
    int tr[N];

    void modify(int x, int d)
    {
        for (; x <= n; x += x & -x)
            tr[x] += d;
    }
    int query(int x)
    {
        int sum = 0;
        for (; x; x -= x & -x)
            sum += tr[x];
        return sum;
    }
};
  • 区间加区间和树状树组

\[s_r=(r+1)\sum\limits_{i=1}^rd_i-\sum\limits_{i=1}^r{i \times d_i} \]

struct BitIndexTree
{
    int tr[2][N];

    void _modify(int k, int x, int d)
    {
        for (; x <= n; x += x & -x)
            tr[k][x] += d;
    }
    int _query(int k, int x)
    {
        int sum = 0;
        for (; x; x -= x & -x)
            sum += tr[k][x];
        return sum;
    }
    void modify(int l, int r, int d)
    {
        _modify(0, l, d);
        _modify(0, r + 1, -d);
        _modify(1, l, l * d);
        _modify(1, r + 1, -(r + 1) * d);
    }
    int query(int l, int r)
    {
        return ((r + 1) * _query(0, r) - _query(1, r)) -
               (l * _query(0, l - 1) - _query(1, l - 1));
    }
};
  • 二维树状树组
struct BitIndexTree
{
    int tr[N][N];

    void modify(int x, int y, int d)
    {
        for (int i = x; i <= n; i += i & -i)
            for (int j = y; j <= n; j += j & -j)
                tr[i][j] += d;
    }
    int query(int x, int y)
    {
        int sum = 0;
        for (int i = x; i; i -= i & -i)
            for (int j = y; j; j -= j & -j)
                sum += tr[i][j];
        return sum;
    }
};

4.线段树

  • 普通线段树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
#define mid ((s + t) >> 1)
    struct Node
    {
        int v;
    } tr[N << 2];

    void build(int p, int s, int t)
    {
        v(p) = 0;
        if (s == t)
            return;
        build(ls(p), s, mid);
        build(rs(p), mid + 1, t);
    }
    void pushUp(int p)
    {
        // v(p) = ...
    }
    void modify(int p, int s, int t, int x, int d)
    {
        if (x < s || t < x)
            return;
        if (s == t)
        {
            // v(p) = ...
            return;
        }
        modify(ls(p), s, mid, x, d);
        modify(rs(p), mid + 1, t, x, d);
        pushUp(p);
    }
    int query(int p, int s, int t, int l, int r)
    {
        if (r < s || t < l)
            return 0;
        if (l <= s && t <= r)
            return v(p);
        int lft = query(ls(p), s, mid, l, r);
        int rgh = query(rs(p), mid + 1, t, l, r);
        int rsl;
        // rsl = ...
        return rsl;
    }
};
  • 动态开点线段树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) tr[p].ls
#define rs(p) tr[p].rs
#define mid ((s + t) >> 1)
    struct Node
    {
        int ls, rs, v;
    } tr[N << 5];
    int tot;

    void pushUp(int p)
    {
        if (ls(p))
            // v(p) = ...
        if (rs(p))
            // v(p) = ...
    }
    void modify(int &p, int s, int t, int x, int d)
    {
        if (x < s || t < x)
            return;
        if (!p)
            p = ++tot;
        if (s == t)
        {
            // v(p) = ...
            return;
        }
        modify(ls(p), s, mid, x, d);
        modify(rs(p), mid + 1, t, x, d);
        pushUp(p);
    }
    int query(int p, int s, int t, int l, int r)
    {
        if (r < s || t < l || !p)
            return 0;
        if (l <= s && t <= r)
            return v(p);
        int lft = query(ls(p), s, mid, l, r);
        int rgh = query(rs(p), mid + 1, t, l, r);
        int rsl;
        // rsl = ...
        return rsl;
    }
};
  • 主席树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) tr[p].ls
#define rs(p) tr[p].rs
#define mid ((s + t) >> 1)
    struct Node
    {
        int ls, rs, v;
    } tr[N << 5];
    int tot;

    void build(int &p, int s, int t)
    {
        p = ++tot;
        if (s == t)
            return;
        build(ls(p), s, mid);
        build(rs(p), mid + 1, t);
    }
    void pushUp(int p)
    {
        // v(p) = ...
    }
    void insert(int &p, int q, int s, int t, int x, int d)
    {
        if (x < s || t < x)
            return;
        p = ++tot, tr[p] = tr[q];
        if (s == t)
        {
            // v(p) = ...
            return;
        }
        insert(ls(p), ls(q), s, mid, x, d);
        insert(rs(p), rs(q), mid + 1, t, x, d);
        pushUp(p);
    }
    int query(int p, int s, int t, int l, int r)
    {
        if (r < s || t < l)
            return 0;
        if (l <= s && t <= r)
            return v(p);
        int lft = query(ls(p), s, mid, l, r);
        int rgh = query(rs(p), mid + 1, t, l, r);
        int rsl;
        // rsl = ...
        return rsl;
    }
};

5.线段树分治

struct SegmentTree
{
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
#define mid ((s + t) >> 1)
    vector<Node> tr[N << 2];

    void modify(int p, int s, int t, int l, int r, Node d)
    {
        if (r < s || t < l)
            return;
        if (l <= s && t <= r)
        {
            tr[p].push_back(d);
            return;
        }
        modify(ls(p), s, mid, l, r, d);
        modify(rs(p), mid + 1, t, l, r, d);
    }
} seg;

stack<int> his;
void undo(int tim)
{
    while(his.size() > tim) {
        // remove his.top() ...
        his.pop();
    }
}

void solve(int p, int s, int t)
{
    int rec = his.size();
    for (Node x : seg.tr[p])
    {
        // insert x ...
    }
    if (s == t)
    {
        // rsl = ...
        undo(rec);
        return;
    }
    undo(rec);
    solve(ls(p), s, mid);
    solve(rs(p), mid + 1, t);
}

6.CDQ分治

stack<int> rec;
void cdq(int s, int t)
{
    if (s >= t)
        return;
    int mid = (s + t) >> 1;

    cdq(s, mid);

    sort(a + s, a + mid + 1, cmpB);
    sort(a + mid + 1, a + t + 1, cmpB);

    for (int i = mid + 1, j = s - 1; i <= t; ++i)
    {
        while (j < mid && a[j + 1].v < a[i].v) {
            ++j;
            // insert a[j] ...
            rec.push(a[j].p);
        }
        // rsl = ...
    }

    while (rec.size()) {
        // remove rec.top() ...
        rec.pop();
    } 

    sort(a + mid + 1, a + t + 1, cmpA);
    cdq(mid + 1, t);
}

7.整体二分

int qid[N], now;
vector<int> lft, rgh;
void solve(int s, int t, int l, int r)
{
    if (s > t || l > r)
        return;
    if (s == t)
    {
        // rsl = ...
        return;
    }
    int mid = (s + t) >> 1;

    while (now < mid)
    {
        ++now;
        // insert now ...
    }
    while (now > mid)
    {
        // remove now ...
        --now;
    }

    lft.clear(), rgh.clear();
    for (int i = l; i <= r; ++i)
    {
        if (/* check... */)
            lft.push_back(qid[i]);
        else
            rgh.push_back(qid[i]);
    }

    for (int i = 0; i < lft.size(); ++i)
        qid[l + i] = lft[i];
    for (int i = 0; i < rgh.size(); ++i)
        qid[l + lft.size() + i] = rgh[i];

    int siz = lft.size();
    solve(s, mid, l, l + lft.size() - 1);
    solve(mid + 1, t, l + siz, r);
}

8.*数列分块

#define lft(x) ((x - 1) * siz + 1)
#define rgh(x) min(lft(x + 1) - 1, n)
#define idx(x) ((x - 1) / siz + 1)
int siz, tot, val[M][M];

inline void init()
{
    siz = sqrt(n), tot = (n + siz - 1) / siz;

    for (int i = 1; i <= tot; ++i)
        for (int j = i; j <= tot; ++j)
        {
            // val[i][j] = ...
        }
}

inline int query(int l, int r)
{
    int lft = idx(l), rgh = idx(r);
    if (rgh - lft <= 1)
    {
        int rsl = 0;
        for (int i = l; i <= r; ++i)
        {
            // rsl = ...
        }
        return rsl;
    }
    int rsl = val[lft + 1][rgh - 1];

    for (int i = l; i <= rgh(lft); ++i)
    {
        // rsl = ...
    }
    for (int i = lft(rgh); i <= r; ++i)
    {
        // rsl = ...
    }
    return rsl;
}

9.*莫队

#define idx(x) ((x - 1) / siz + 1)
int siz;

struct Query
{
    int l, r, id;
    inline bool operator<(const Query &b) const
    {
        int b1 = idx(l), b2 = idx(b.l);
        if (b1 != b2)
            return b1 < b2;
        return (b1 & 1) ? (r < b.r) : (r > b.r);
    }
} q[M];

void add(int x)
{
    // insert a[x] ...
}
void del(int x)
{
    // delete a[x] ...
}

void solve()
{
    siz = sqrt(n);
    sort(q + 1, q + m + 1);
    for (int i = 1, l = 1, r = 0; i <= m; ++i)
    {
        while (l > q[i].l)
            add(--l);
        while (r < q[i].r)
            add(++r);
        while (l < q[i].l)
            del(l++);
        while (r > q[i].r)
            del(r--);
        // rsl[q[i].id] = ...
    }
}

图论

1.倍增LCA

vector<int> g[N];
int dep[N], par[N][T + 1];

void dfs(int u, int fa)
{
    dep[u] = dep[fa] + 1, par[u][0] = fa;
    for (int i = 1; i <= T; ++i)
        par[u][i] = par[par[u][i - 1]][i - 1];
    for (int v : g[u])
        if (v != fa)
            dfs(v, u);
}
int getLca(int u, int v)
{
    if (dep[u] > dep[v])
        swap(u, v);
    for (int i = T; i >= 0; --i)
        if (dep[par[v][i]] >= dep[u])
            v = par[v][i];
    if (u == v)
        return u;
    for (int i = T; i >= 0; --i)
        if (par[u][i] != par[v][i])
            u = par[u][i], v = par[v][i];
    return par[u][0];
}

2.最短路

  • Dijkstra
vector<pair<int, int>> g[N];
int dis[N];

void dijkstra(int s)
{
    priority_queue<pair<int, int>> q;
    vector<bool> vis(n + 5);
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    q.push({0, s});

    while (q.size())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (auto [v, w] : g[u])
        {
            if (dis[u] + w < dis[v])
            {
                dis[v] = dis[u] + w;
                q.push({-dis[v], v});
            }
        }
    }
}
  • Floyd
int g[N][N];

void floyd()
{
    for (int k = 1; k <= n; ++k)
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}

3.树的重心

  1. 树以重心为根时,任一子树大小不超过原树大小的一半.

  2. 树的重心如果不唯一,则恰有两个,这两个重心相邻.

  3. 树上添/删一个叶子,重心最多只移动一条边.

  4. 两棵树通过一条边相连,那么新树的重心在连接原来两棵树的重心的路径上.

  5. 树上所有的点到树的重心的距离之和最短.

int siz[N], f[N], root;

void dfs(int u, int fa)
{
    siz[u] = 1, f[u] = 0;
    for (int v : g[u])
    {
        if (v == fa)
            continue;
        dfs(v, u);
        siz[u] += siz[v];
        f[u] = max(f[u], siz[v]);
    }
    f[u] = max(f[u], n - siz[u]);
    if (f[u] <= (n >> 1))
        root = u;
}

4.最小生成树

  • Kruskal
int Kruskal()
{
    int rsl = 0;
    sort(edg + 1, edg + m + 1, [](Edge &a, Edge &b)
         { return a.w < b.w; });
    for (int i = 1; i <= m; ++i)
    {
        auto [u, v, w] = edg[i];
        u = dsu.find(u), v = dsu.find(v);
        if(u == v) continue;
        dsu.fa[u] = v, rsl += w;
    }
    return rsl;
}
  • Prim
int Prim()
{
    int rsl = 0;
    vector<int> d(n + 5, 1e9);
    vector<bool> vis(n + 5);
    d[1] = 0;

    for (int i = 1; i <= n; ++i)
    {
        int u = 0;
        for (int v = 1; v <= n; ++v)
            if (!vis[v] && d[v] < d[u])
                u = v;

        rsl += d[u], vis[u] = 1;

        for (int v = 1; v <= n; ++v)
            if (!vis[v])
                d[v] = min(d[v], g[u][v]);
    }
    return rsl;
}

5.Tarjan

  • 强连通分量
vector<int> g[N];
int dfn[N], tim, low[N], scc[N], siz[N], tot;
bool ins[N];
stack<int> stc;

void tarjan(int u)
{
    dfn[u] = low[u] = ++tim;
    stc.push(u), ins[u] = 1;
    for (int v : g[u])
    {
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u])
    {
        ++tot;
        while (1)
        {
            int v = stc.top();
            stc.pop();
            ins[v] = 0, scc[v] = tot;
            if (v <= n)
                ++siz[tot];
            if (v == u)
                break;
        }
    }
}
  • 割辺
struct edg
{
    int v, nex;
} edg[M];
int head[N], tot = 1;
int dfn[N], low[N], tim, dcc[N], cnt;
bool cut[N];

void tarjan(int u, int in)
{
    dfn[u] = low[u] = ++tim;
    for (int i = head[u]; i; i = edg[i].nex)
    {
        int v = edg[i].v;
        if (!dfn[v])
        {
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
                cut[i] = cut[i ^ 1] = 1;
        }
        else if (i != (in ^ 1))
            low[u] = min(low[u], dfn[v]);
    }
}
  • 割点/圆方树
vector<int> g[N], dcc[N];
int dfn[N], low[N], tim, root, tot;
bool cut[N];
stack<int> stc;

void tarjan(int u)
{
    dfn[u] = low[u] = ++tim;
    if (u == root && !g[u].size())
    {
        dcc[++tot].push_back(u);
        return;
    }
    int flag = 1;
    stc.push(u);

    for (int v : g[u])
    {
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u])
            {
                ++flag;
                if (u != root || flag > 1)
                    cut[u] = 1;
                ++tot;
                while (1)
                {
                    int w = stc.top();
                    stc.pop();
                    dcc[tot].push_back(w);
                    if (w == v)
                        break;
                }
                stc.push(u);
            }
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
}

6.欧拉路

  1. 有向图欧拉路径:图中恰好存在 \(1\) 点出度 = 入度 + \(1\)(即 \(S\) ).

  2. 有向图欧拉回路:所有点的入度 = 出度( \(S\)\(T\) 任意).

  3. 无向图欧拉路径:图中恰好存在 \(2\) 点的度数是奇数,即 \(S\)\(T\).

  4. 无向图欧拉回路:所有点的度数都是偶数\(S\)\(T\) 任意).

  • 有向图欧拉路径
multiset<int> g[N];
stack<int> path;

void dfs(int u)
{
    while (g[u].size())
    {
        auto p = g[u].begin();
        g[u].erase(p);
        dfs(*p);
    }
    path.push(u);
}
void printPath()
{
    while (path.size())
    {
        cout << path.top() << ' ';
        path.pop();
    }
    cout << '\n';
}
  • 无向图

有向图基础上增加判断来边即可(注意重边).

7.树上启发式合并

vector<int> g[N];
int siz[N], son[N], rsl[N];

void pre(int u)
{
    siz[u] = 1;
    for (int v : g[u])
    {
        pre(v), siz[u] += siz[v];
        son[u] = siz[v] > siz[son[u]] ? v : son[u];
    }
}

void add(int u, int d)
{
    // insert/remove u ...
    for (int v : g[u])
        add(v, d);
}

void dfs(int u, bool type)
{
    for (int v : g[u])
        if (v != son[u])
            dfs(v, 0);
    if (son[u])
        dfs(son[u], 1);
    for (int v : g[u])
        if (v != son[u])
            add(v, 1);

    // insert u ...
    // calculate u's result ...
    if (!type)
        add(u, -1);
}

8.*重链剖分

vector<int> g[N];
int dep[N], par[N], siz[N], son[N];
int dfn[N], top[N], tim;

void dfs1(int u, int fa)
{
    dep[u] = dep[fa] + 1, par[u] = fa, siz[u] = 1;
    for (int v : g[u])
    {
        if (v == fa)
            continue;
        dfs1(v, u);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]])
            son[u] = v;
    }
}
void dfs2(int u, int t)
{
    dfn[u] = ++tim, top[u] = t;
    if (!son[u])
        return;
    dfs2(son[u], t);
    for (int v : g[u])
        if (v != par[u] && v != son[u])
            dfs2(v, v);
}
int query(int u, int v)
{
    int rsl = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        // rsl = ...
        u = par[top[u]];
    }

    if (dep[u] < dep[v])
        swap(u, v);
    // rsl = ...
    return rsl;
}

9.*点分治

bool vis[N];
int tot, siz[N], root;

void getRoot(int u, int fa)
{
    siz[u] = 1;
    int f = 0;
    for (auto [v, w] : g[u])
    {
        if (vis[v] || v == fa)
            continue;
        getRoot(v, u);
        siz[u] += siz[v], f = max(f, siz[v]);
    }
    f = max(f, tot - siz[u]);
    if (f <= (tot >> 1))
        root = u;
}

int dis[N];
unordered_map<int, int> cnt;

void modify(int u, int fa, int d)
{
    cnt[dis[u]] += d;

    for (auto [v, w] : g[u])
        if (!vis[v] && v != fa)
            modify(v, u, d);
}

void query(int u, int fa)
{
    // rsl = ...
    for (auto [v, w] : g[u])
        if (!vis[v] && v != fa)
            dis[v] = dis[u] + w, query(v, u);
}

void calc(int u)
{
    dis[u] = 0;
    for (auto [v, w] : g[u])
    {
        if (vis[v])
            continue;
        dis[v] = w;
        query(v, u);
        modify(v, u, 1);
    }
    modify(u, 0, -1);
}

void solve(int u)
{
    vis[u] = 1;
    calc(u);
    int rec = tot;
    for (auto [v, w] : g[u])
    {
        if (vis[v])
            continue;
        tot = siz[v] < siz[u] ? siz[v] : rec - siz[u];
        getRoot(v, u);
        solve(root);
    }
}

数学

1.exgcd

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

2.逆元

  • exgcd求逆元
int inv(int n)
{
    int x, y;
    exgcd(n, P, x, y);
    return (x % P + P) % P;
}
  • 线性预处理逆元
int inv[N];

void init()
{
    inv[1] = 1;
    for (int i = 2; i <= n; ++i)
        inv[i] = inv[P % i] * (P - P / i) % P;
}

3.线性筛

vector<int> pri;
void getPri(int n)
{
    vector<bool> vis(n + 5);
    for (int i = 2; i <= n; ++i)
    {
        if (!vis[i])
            pri.push_back(i);
        for (int p : pri)
        {
            if (p > n / i)
                break;
            vis[p * i] = 1;
            if (i % p == 0)
                break;
        }
    }
}

4.Lucas定理

int lucas(int n, int m)
{
    return m ? lucas(n / P, m / P) * C(n % P, m % P) % P : 1;
}

5.同余最短路

for (int i = 0; i < mn; ++i)
    for (int j = 2; j <= n; ++j)
        g[i].push_back({(i + a[j]) % mn, a[j]});

dijkstra(0);

int rsl = 0;
for (int i = 0; i < mn; ++i)
{
    if (dis[i] <= r)
        rsl += (r - dis[i]) / mn + 1;
    if (dis[i] <= l - 1)
        rsl -= (l - 1 - dis[i]) / mn + 1;
}

6.矩阵

\[c_{i,j}=\sum\limits_{k=1}^m{a_{i,k} \times b_{k,j}} \]

  • 矩阵乘法
struct Matrix
{
    int n, m;
    vector<vector<int>> a;
    Matrix(int _n, int _m)
    {
        n = _n, m = _m;
        a.resize(n + 1);
        for (int i = 1; i <= n; ++i)
            a[i].resize(m + 1);
    };
    Matrix operator*(const Matrix &b)
    {
        assert(m == b.n);
        Matrix c(n, b.m);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= b.m; ++j)
                for (int k = 1; k <= m; ++k)
                    (c.a[i][j] += a[i][k] * b.a[k][j] % P) %= P;
        return c;
    }
};
  • 矩阵快速幂
Matrix power(Matrix n, int m)
{
    assert(n.n == n.m);
    Matrix rsl(n.n, n.n);
    for (int i = 1; i <= n.n; ++i)
        rsl.a[i][i] = 1;
    for (; m; m >>= 1, n = n * n)
        if (m & 1)
            rsl = rsl * n;
    return rsl;
}

7.高斯消元

long double a[N], b[N], c[N][N];

void guass()
{
    for (int i = 1; i <= n; ++i)
    {
        for (int j = i; j <= n; ++j)
        {
            if (abs(c[j][i] <= 1e-8))
                continue;
            swap(c[i], c[j]), swap(b[i], b[j]);
            break;
        }

        for (int j = 1; j <= n; ++j)
        {
            if (i == j)
                continue;
            ldb rate = c[j][i] / c[i][i];
            for (int k = i; k <= n; ++k)
                c[j][k] -= c[i][k] * rate;
            b[j] -= b[i] * rate;
        }
    }
    for (int i = 1; i <= n; ++i)
        a[i] = b[i] / c[i][i];
}

8.*异或线性基

int base[N];

bool insert(int x)
{
    for (int i = T; i >= 0; --i)
    {
        if (!((x >> i) & 1))
            continue;
        if (!base[i])
        {
            base[i] = x;
            return 1;
        }
        x ^= base[i];
    }
    return 0;
}

字符串

1.哈希

  • 一维哈希
#define ull unsigned long long
#define B 45141
int pwe[N], a[N], s[N];

void init()
{
    for (int i = 1; i <= n; ++i)
        pwe[i] = pwe[i - 1] * B;
    for (int i = 1; i <= n; ++i)
        s[i] = s[i - 1] * B + a[i];
}
ull query(int l, int r)
{
    return s[r] - s[l - 1] * pwe[r - l + 1];
}
  • 二维哈希
#define ull unsigned long long
#define B1 1451
#define B2 45141
ull pwe[0][N], a[N][N], s[N][N];

void init()
{
    pwe[0][0] = pwe[1][0] = 1;
    for (int i = 1; i <= max(n, m); ++i)
    {
        pwe[0][i] = pwe[0][i - 1] * B1;
        pwe[1][i] = pwe[1][i - 1] * B2;
    }
    for (int i = 1; i <= n; ++i)
    {
        ull val = 0;
        for (int j = 1; j <= m; ++j)
        {
            val = val * B1 + (ull)a[i][j];
            s[i][j] = val + s[i - 1][j] * B2;
        }
    }
}
ull get(int x1, int y1, int x2, int y2)
{
    int a = x2 - x1 + 1, b = y2 - y1 + 1;
    return s[x2][y2] -
           s[x1 - 1][y2] * pwe[1][a] -
           s[x2][y1 - 1] * pwe[0][b] +
           s[x1 - 1][y1 - 1] * pwe[1][a] * pwe[0][b];
}

2.KMP

string s, t;
int n, m, nex[N], f[N];

for (int i = 2, j = 0; i <= m; ++i)
{
    while (j && t[j + 1] != t[i])
        j = nex[j];
    if (t[j + 1] == t[i])
        ++j;
    nex[i] = j;
}
for (int i = 1, j = 0; i <= n; ++i)
{
    while (j && (j == m || t[j + 1] != s[i]))
        j = nex[j];
    if (t[j + 1] == s[i])
        ++j;
    f[i] = j;
}

3.Manacher

int manacher(string &str)
{
    vector<int> f(n + 5);
    int ans = 0;
    vector<char> s;
    s.push_back(' ');
    s.push_back(' ');
    for (int i = 0; i < (int)str.size(); ++i)
    {
        s.push_back(str[i]);
        s.push_back(' ');
    }
    for (int i = 1, mid = 0, r = 0; i < (int)s.size(); ++i)
    {
        if (i <= r)
            f[i] = min(f[(mid << 1) - i], r - i + 1);
        while (s[i - f[i]] == s[i + f[i]])
            ++f[i];
        if (i + f[i] > r)
            r = i + f[i] - 1, mid = i;
        ans = max(ans, f[i]);
    }
    return ans - 1;
}

4.最小表示法

string s;

int i = 1, j = 2;
for (int k = 0; i <= n && j <= n && k < n;)
{
    char a = s[(i + k) % n + 1];
    char b = s[(j + k) % n + 1];
    if (a == b)
        ++k;
    else
    {
        if (a > b)
            i += k + 1;
        else
            j += k + 1;
        if (i == j)
            ++i;
        k = 0;
    }
}
i = min(i, j);

5.字典树

struct Trie
{
    int tr[M][26], val[M], tot = 1;

    void insert(string &s)
    {
        int p = 1;
        for (int i = 0; i < s.size(); ++i)
        {
            ++val[p];
            int w = s[i] - 'a';
            if (!tr[p][w])
                tr[p][w] = ++tot;
            p = tr[p][w];
        }
        ++val[p];
    }
};

杂项

1.单调队列/栈

  • 单调队列
deque<int> q;

for (int i = 1; i <= n; i++)
{
    while (!q.empty() && a[i] < a[q.back()])
        q.pop_back();
    q.push_back(i);
    if (i - q.front() >= k)
        q.pop_front();
    if (i >= k)
        f[i] = q.front();
}
  • 单调栈
stack<int> stc;

for (int i = 1; i <= n; ++i)
{
    while (stc.size() && a[stc.top()] < a[i])
        f[stc.top()] = i, stc.pop();
    stc.push(i);
}

2.反悔贪心

prioirty_queue<int> q;

for (int i = 1, t = 0; i <= n; ++i)
{
    if (t + a[i].w <= a[i].l)
    {
        t += a[i].w;
        q.push(a[i].w);
    }
    else if (q.size() && q.top() > a[i].w)
    {
        t -= q.top();
        q.pop(), q.push(a[i].w);
        t += a[i].w;
    }
}

3.单调队列优化多重背包

int n, m, v[N], w[N], k[N], f[2][M];

int g(int i, int y, int x)
{
    return f[i & 1 ^ 1][x * w[i] + y] - x * v[i];
}

for (int i = 1; i <= n; ++i)
    for (int y = 0; y < w[i]; ++y)
    {
        deque<int> q;
        for (int x = 0; x * w[i] + y <= m; ++x)
        {
            while (q.size() && x - q.front() > k[i])
                q.pop_front();
            while (q.size() && g(i, y, q.back()) <= g(i, y, x))
                q.pop_back();
            q.push_back(x);
            f[i & 1][x * w[i] + y] = v[i] * x + g(i, y, q.front());
        }
    }

4.*模拟退火

  1. 求最大值:\(P(\delta)=e^{\frac{\delta}{t}}\)

  2. 求最小值:\(P(\delta)=e^{-\frac{\delta}{t}}\)

#define dbl double
dbl ans;
dbl getRand()
{
    return rand() % 100000 / 100000.0;
}
dbl getAns()
{
    dbl tmp;
    // calculate the temp answer...
    ans = max(ans, tmp);
    return tmp;
}

void SA(dbl beg, dbl end, dbl dec, int cnt)
{
    dbl t = beg, now = ans;
    while (t > end)
    {
        int x = rand() % n + 1, y = rand() % n + 1;
        if (x == y)
            continue;
        swap(a[x], a[y]);
        dbl tmp = getAns();
        if (tmp < now || exp(-(tmp - now) / t) > getRand())
            now = tmp;
        else
            swap(a[x], a[y]);
        t *= dec;
    }
    for (int i = 1; i <= cnt; ++i)
    {
        int x = rand() % n + 1, y = rand() % n + 1;
        if (x == y)
            continue;
        swap(a[x], a[y]);
        getAns();
        swap(a[x], a[y]);
    }
}
posted @ 2025-04-15 18:58  xiangixuan  阅读(45)  评论(0)    收藏  举报