欢迎来到 xht37 的博客

Trick

基础

IO

  • 模板
namespace io {
    const int SIZE = (1 << 21) + 1;
    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55];
    int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++)
    inline void flush() {
        fwrite(obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
    inline void putc(char x) {
        *oS++ = x;
        if (oS == oT) flush();
    }
    template <class I>
    inline void rd(I &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
        x *= f;
    }
    template <class I>
    inline void print(I x) {
        if (!x) putc('0');
        if (x < 0) putc('-'), x = -x;
        while (x) qu[++qr] = x % 10 + '0', x /= 10;
        while (qr) putc(qu[qr--]);
        putc('\n');
    }
    struct Flusher_ {
        ~Flusher_() {
            flush();
        }
    } io_flusher_;
}
using io::rd;
using io::print;

二分

  • 求单调序列中数 \(x\) 的个数
upper_bound(a + 1, a + n + 1, x) - lower_bound(a + 1, a + n + 1, x);

Hash

  • 单个元素映射多维随机权值

  • set实现Hash表

字符串

SA

  • 模板
namespace SA {
    const int N = ...;
    int n, m = ..., sa[N], rk[N], tp[N], tx[N], he[N], st[N][...];
    char s[N];

    inline void tsort() {
        for (int i = 1; i <= m; i++) tx[i] = 0;
        for (int i = 1; i <= n; i++) ++tx[rk[i]];
        for (int i = 1; i <= m; i++) tx[i] += tx[i-1];
        for (int i = n; i; i--) sa[tx[rk[tp[i]]]--] = tp[i];
    }

    inline bool pd(int i, int w) {
        return tp[sa[i-1]] == tp[sa[i]] && tp[sa[i-1]+w] == tp[sa[i]+w];
    }

    inline void main() {
        for (int i = 1; i <= n; i++) rk[i] = s[i] - 'a' + 1, tp[i] = i;
        tsort();
        for (int w = 1, p = 0; p < n; w <<= 1, m = p) {
            p = 0;
            for (int i = 1; i <= w; i++) tp[++p] = n - w + i;
            for (int i = 1; i <= n; i++) if (sa[i] > w) tp[++p] = sa[i] - w;
            tsort(), swap(rk, tp), rk[sa[1]] = p = 1;
            for (int i = 2; i <= n; i++) rk[sa[i]] = pd(i, w) ? p : ++p;
        }
        int p = 0;
        for (int i = 1; i <= n; i++) {
            if (p) --p;
            int j = sa[rk[i]-1];
            while (s[i+p] == s[j+p]) ++p;
            he[rk[i]] = p;
        }
        for (int i = 1; i <= n; i++) st[i][0] = he[i];
        int w = log(n) / log(2);
        for (int k = 1; k <= w; k++)
            for (int i = 1; i + (1 << k) - 1 <= n; i++)
                st[i][k] = min(st[i][k-1], st[i+(1<<(k-1))][k-1]);
    }

    inline int get(int l, int r) {
        int k = log(r - l + 1) / log(2);
        return min(st[l][k], st[r-(1<<k)+1][k]);
    }
}

数据结构

Treap

  • 模板
namespace Treap {
    const int N = ..., inf = 1e9;
    int t, rt;
    struct T {
        int l, r, x, k, c, s;
    } a[N];

    inline int add(int x) {
        a[++t].x = x;
        a[t].k = rand();
        a[t].c = a[t].s = 1;
        return t;
    }

    inline void upd(int p) {
        a[p].s = a[a[p].l].s + a[a[p].r].s + a[p].c;
    }

    inline void zig(int &p) {
        int q = a[p].l;
        a[p].l = a[q].r;
        a[q].r = p;
        p = q;
        upd(a[p].r);
        upd(p);
    }

    inline void zag(int &p) {
        int q = a[p].r;
        a[p].r = a[q].l;
        a[q].l = p;
        p = q;
        upd(a[p].l);
        upd(p);
    }

    void ins(int &p, int x) {
        if (!p) {
            p = add(x);
            return;
        }
        if (x == a[p].x) {
            a[p].c++;
            upd(p);
            return;
        }
        if (x < a[p].x) {
            ins(a[p].l, x);
            if (a[p].k < a[a[p].l].k) zig(p);
        } else {
            ins(a[p].r, x);
            if (a[p].k < a[a[p].r].k) zag(p);
        }
        upd(p);
    }

    void del(int &p, int x) {
        if (!p) return;
        if (x == a[p].x) {
            if (a[p].c > 1) {
                --a[p].c;
                upd(p);
                return;
            }
            if (a[p].l || a[p].r) {
                if (!a[p].r || a[a[p].l].k > a[a[p].r].k) {
                    zig(p);
                    del(a[p].r, x);
                } else {
                    zag(p);
                    del(a[p].l, x);
                }
                upd(p);
            } else p = 0;
            return;
        }
        x < a[p].x ? del(a[p].l, x) : del(a[p].r, x);
        upd(p);
    }

    int rnk(int p, int x) {
        if (!p) return 0;
        if (x == a[p].x) return a[a[p].l].s + 1;
        if (x < a[p].x) return rnk(a[p].l, x);
        return rnk(a[p].r, x) + a[a[p].l].s + a[p].c;
    }
    
    inline int askrnk(int p, int x) {
        return rnk(p, x) - 1;
    }

    int kth(int p, int k) {
        if (!p) return inf;
        if (a[a[p].l].s >= k) return kth(a[p].l, k);
        if (a[a[p].l].s + a[p].c >= k) return a[p].x;
        return kth(a[p].r, k - a[a[p].l].s - a[p].c);
    }
    
    inline int askkth(int p, int k) {
        return kth(p, k + 1);
    }

    inline int pre(int x) {
        int ans = 1, p = rt;
        while (p) {
            if (x == a[p].x) {
                if (a[p].l > 0) {
                    p = a[p].l;
                    while (a[p].r > 0) p = a[p].r;
                    ans = p;
                }
                break;
            }
            if (a[p].x < x && a[p].x > a[ans].x) ans = p;
            p = x < a[p].x ? a[p].l : a[p].r;
        }
        return a[ans].x;
    }

    inline int nxt(int x) {
        int ans = 2, p = rt;
        while (p) {
            if (x == a[p].x) {
                if (a[p].r > 0) {
                    p = a[p].r;
                    while (a[p].l > 0) p = a[p].l;
                    ans = p;
                }
                break;
            }
            if (a[p].x > x && a[p].x < a[ans].x) ans = p;
            p = x < a[p].x ? a[p].l : a[p].r;
        }
        return a[ans].x;
    }

    inline int build() {
        srand(time(0));
        rt = add(-inf);
        a[rt].r = add(inf);
        upd(rt);
        return rt;
    }
}

LCT

  • 模板
namespace LCT {
#define nort(x) (t[t[x].f].ch[0] == x || t[t[x].f].ch[1] == x)
#define get(x) (t[t[x].f].ch[1] == x)
#define rev(x) swap(t[x].ch[0], t[x].ch[1]), t[x].r ^= 1
    const int N = ...;
    struct T {
        int f, ch[2], r, s, ...;
    } t[N];

    inline void upd(int x) {
        t[x].s = t[t[x].ch[0]].s + t[t[x].ch[1]].s + 1;
        ...
    }

    inline void spread(int x) {
        if (t[x].r) {
            if (t[x].ch[0]) rev(t[x].ch[0]);
            if (t[x].ch[1]) rev(t[x].ch[1]);
            t[x].r = 0;
        }
        ...
    }

    inline void rot(int x) {
        int y = t[x].f, z = t[y].f, k = get(x), w = get(y);
        if (t[x].ch[k^1]) t[t[x].ch[k^1]].f = y;
        t[y].ch[k] = t[x].ch[k^1];
        t[x].f = z;
        if (nort(y)) t[z].ch[w] = x;
        t[y].f = x;
        t[x].ch[k^1] = y;
        upd(y);
    }

    inline void splay(int x) {
        int y = x;
        stack<int> st;
        st.push(y);
        while (nort(y)) {
            y = t[y].f;
            st.push(y);
        }
        while (st.size()) {
            spread(st.top());
            st.pop();
        }
        while (nort(x)) {
            y = t[x].f;
            if (nort(y)) rot(get(x) == get(y) ? y : x);
            rot(x);
        }
        upd(x);
    }

    inline void access(int x) {
        int y = 0;
        while (x) {
            splay(x);
            t[x].ch[1] = y;
            upd(x);
            y = x;
            x = t[y].f;
        }
    }

    inline void mkrt(int x) {
        access(x);
        splay(x);
        rev(x);
    }

    inline int fdrt(int x) {
        access(x);
        splay(x);
        while (t[x].ch[0]) {
            spread(x);
            x = t[x].ch[0];
        }
        splay(x);
        return x;
    }

    inline void split(int x, int y) {
        mkrt(x);
        access(y);
        splay(y);
    }

    inline void link(int x, int y) {
        mkrt(x);
        if (fdrt(y) != x) t[x].f = y;
    }

    inline void cut(int x, int y) {
        mkrt(x);
        if (fdrt(y) == x && t[y].f == x && !t[y].ch[0]) {
            t[y].f = t[x].ch[1] = 0;
            upd(x);
        }
    }
}

去log

  • 可持久化

  • 离线(CDQ分治/整体二分)

偏序转化

  • 记录前驱(上一次出现位置)

  • 维护值域

  • 树上DFS序

点分治

  • 注意递归时保存树的重心(递归时树的重心会改变)

图论

  • 点边转化

  • 连边模板

const int N = ..., M = ...;
int Head[N], Edge[M], Leng[M], Next[M], tot = 1;

inline void add(int x, int y, int z) {
    Edge[++tot] = y;
    Leng[tot] = z;
    Next[tot] = Head[x];
    Head[x] = tot;
}

  • 无根树不要设 \(1\) 为根

  • 多个点LCA的最深点是dfs序相邻两点的LCA,最浅点是dfs序最远两点的LCA

网络流

  • Dinic模板
namespace Dinic {
    int S = N - 1, T = N - 2, d[N];

    inline bool bfs() {
        memset(d, 0, sizeof(d));
        queue<int> q;
        q.push(S);
        d[S] = 1;
        while (q.size()) {
            int x = q.front();
            q.pop();
            for (int i = Head[x]; i; i = Next[i]) {
                int y = Edge[i], z = Leng[i];
                if (d[y] || !z) continue;
                q.push(y);
                d[y] = d[x] + 1;
                if (y == T) return 1;
            }
        }
        return 0;
    }

    int dinic(int x, int flow) {
        if (x == T) return flow;
        int rest = flow;
        for (int i = Head[x]; i && rest; i = Next[i]) {
            int y = Edge[i], z = Leng[i];
            if (d[y] != d[x] + 1 || !z) continue;
            int k = dinic(y, min(rest, z));
            if (!k) d[y] = 0;
            else {
                Leng[i] -= k;
                Leng[i^1] += k;
                rest -= k;
            }
        }
        return flow - rest;
    }

    inline int work() {
        int now = 0, maxflow = 0;
        while (bfs())
            while ((now = dinic(S, inf)))
                maxflow += now;
        return maxflow;
    }
}
  • 权值有正有负,重复选只算一次,选了某些东西就得选其他东西——最大权闭合子图

动态规划

期望DP

  • 逆序倒推

  • 分离随机变量(利用期望的线性性)

状压DP

  • 枚举子集
for (int i = s; i; i = (i - 1) & s)

数学

数论&组合

  • 快速幂
#define ll long long

inline int ksm(int a, ll b, int p) {
    int c = 1 % p;
    while (b) {
        if (b & 1) c = (ll)c * a % p;
        a = (ll)a * a % p, b >>= 1;
    }
    return c;
}
  • 欧几里得算法
int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
  • 扩展欧几里得算法
int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, x, y), z = x;
    x = y, y = z - y * (a / b);
    return d;
}
  • 欧拉函数&莫比乌斯函数线性筛
int miu[N], phi[N], v[N], p[N], c;

inline void prework(int n) {
    miu[1] = phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!v[i]) {
            v[i] = p[++c] = i;
            miu[i] = -1;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= c && p[j] * i <= n && p[j] <= v[i]; j++) {
            v[p[j]*i] = p[j];
            miu[p[j]*i] = p[j] == v[i] ? 0 : -miu[i];
            phi[p[j]*i] = phi[i] * (p[j] == v[i] ? p[j] : p[j] - 1);
        }
    }
}
  • \(\sum_{d=1}^{n}\ \lfloor \frac{n}{d} \rfloor = O(n\ log\ n)\)

  • \(\varphi *1 = id\)

  • \(\mu * 1 = \epsilon\)

  • \(d(ij) = \sum_{x|i}\ \sum_{y|j}\ [gcd(x,y)==1]\)

  • 杜教筛:递归的 \(x\) 如果不超过 \(n ^ \frac{2}{3}\) 就查表,否则存到 \(ff[n/x]\) 的位置

  • 错排公式: \(f_1 = 0, f_2 = 1, f_i = (i - 1)(f_{i-1} + f_{i-2})\)

矩阵

  • 模板
#define ll long long

namespace matrix {
    const int N = ..., P = ...;
    struct mat {
        int n, m, a[N][N];
        inline mat() {
            memset(a, 0, sizeof(a));
        }

        inline void init() {
            for (int i = 1; i <= n; i++) a[i][i] = 1;
        }
    };

    inline mat operator * (const mat x, const mat y) {
        mat z;
        z.n = x.n, z.m = y.m;
        int p = x.m;
        for (int i = 1; i <= z.n; i++)
            for (int k = 1; k <= p; k++)
                for (int j = 1; j <= z.m; j++)
                    z.a[i][j] = (ll)(z.a[i][j] + (ll)x.a[i][k] * y.a[k][j] % P) % P;
        return z;
    }
    
    inline mat ksm(mat x, ll y) {
        mat z;
        z.n = z.m = x.n;
        z.init();
        while (y) {
            if (y & 1) z = z * x;
            x = x * x;
            y >>= 1;
        }
        return z;
    }
}

高斯消元

  • 模板
const int N = ...;
const double eps = 1e-10;
double a[N][N], b[N];

inline void Gauss(int n) {
    for (int i = 1; i <= n; i++) {
        int now = i;
        for (int j = i + 1; j <= n; j++)
            if (fabs(a[j][i]) > eps) now = j;
        if (now != i) {
            for (int j = 1; j <= n; j++)
                swap(a[i][j], a[now][j]);
            swap(b[i], b[now]);
        }
        for (int j = 1; j <= n; j++) {
            if (i == j) continue;
            double rate = a[j][i] / a[i][i];
            for (int k = i; k <= n; k++)
                a[j][k] -= a[i][k] * rate;
            b[j] -= b[i] * rate;
        }
    }
}

多项式

  • FFT模板
namespace FFT {
    const int N = ...;
    const double pi = acos(-1.0);
    struct I {
        double x, y;
        inline I(double xx = 0, double yy = 0) {
            x = xx, y = yy;
        }
        inline I operator + (const I a) const {
            return I(x + a.x, y + a.y);
        }
        inline I operator - (const I a) const {
            return I(x - a.x, y - a.y);
        }
        inline I operator * (const I a) const {
            return I(x * a.x - y * a.y, x * a.y + y * a.x);
        }
    } a[N], b[N];
    int n, m, k = 1, l, r[N];

    inline void fft(I *z, int o) {
        for (int i = 0; i < k; i++)
            if (i < r[i]) swap(z[i], z[r[i]]);
        for (int mid = 1; mid < k; mid <<= 1) {
            I W = I(cos(pi / mid), o * sin(pi / mid));
            for (int i = 0; i < k; i += mid << 1) {
                I w = I(1, 0);
                for (int j = 0; j < mid; j++, w = w * W) {
                    I x = z[i+j], y = w * z[i+j+mid];
                    z[i+j] = x + y;
                    z[i+j+mid] = x - y;
                }
            }
        }
    }

    inline void work() {
        while (k <= n + m) k <<= 1, ++l;
        for (int i = 0; i < k; i++)
            r[i] = (r[i>>1] >> 1) | ((i & 1) << (l - 1));
        fft(a, 1);
        fft(b, 1);
        for (int i = 0; i < k; i++) a[i] = a[i] * b[i];
        fft(a, -1);
        for (int i = 0; i <= n + m; i++) a[i].x = abs(a[i].x) / k;
    }
}
  • NTT模板
namespace NTT {
    const int N = ..., P = ..., G = ...;
    int n, m, a[N], b[N], k = 1, l, r[N], invk, invG;
    
    inline int ksm(int a, int b) {
        int c = 1;
        while (b) {
            if (b & 1) c = (ll)c * a % P;
            a = (ll)a * a % P, b >>= 1;
        }
        return c;
    }
    
    inline void ntt(int *z, int o) {
        for (int i = 0; i < k; i++)
            if (i < r[i]) swap(z[i], z[r[i]]);
        for (int mid = 1; mid < k; mid <<= 1) {
            int W = ksm(o == 1 ? G : invG, (P - 1) / (mid << 1));
            for (int i = 0; i < k; i += mid << 1)
                for (int j = 0, w = 1; j < mid; j++, w = (ll)w * W % P) {
                    int x = z[i+j], y = (ll)w * z[i+j+mid] % P;
                    z[i+j] = (x + y) % P;
                    z[i+j+mid] = (x - y + P) % P;
                }
        }
    }

    inline void work() {
        while (k <= n + m) k <<= 1, ++l;
        invk = ksm(k, P - 2), invG = ksm(G, P - 2);
        for (int i = 0; i < k; i++)
            r[i] = (r[i>>1] >> 1) | ((i & 1) << (l - 1));
        ntt(a, 1);
        ntt(b, 1);
        for (int i = 0; i < k; i++) a[i] = (ll)a[i] * b[i] % P;
        ntt(a, -1);
        for (int i = 0; i <= n + m; i++) a[i] = (ll)a[i] * invk % P;
    }
}
  • 翻转卷积

posted @ 2019-03-19 16:09 xht37 阅读(...) 评论(...) 编辑 收藏