突然发现曾经写的一些模版还是上锁的,直接解锁提供给大家了
数论模板
O(1) 快速乘
LL mul(LL a, LL b, LL mod) {
LL t = a*b-(LL)((long double)a/mod*b + 0.5)*mod; t %= mod;
return t < 0 ? t+mod : t;
}
扩展欧几里得
void exgcd(LL a, LL b, LL &x, LL &y, LL &d) {
if (!b) d = a, x = 1, y = 0;
else exgcd(b, a % b, y, x, d), y -= a/b*x;
}
中国剩余定理(构造)
LL crt() {
LL M = 1, ans = 0;
for (int i = 1; i <= n; i++) M *= b[i];
for (int i = 1; i <= n; i++) {
LL x, y, d, m = M/b[i];
exgcd(m, b[i], x, y, d);
(ans += m*x*a[i]) %= M;
}
return ans < 0 ? ans+M : ans;
}
中国剩余定理(合并)
LL excrt() {
LL M = 1, ans = 0;
for (int i = 1; i <= n; i++) {
LL x, y, d, t; exgcd(M, b[i], x, y, d);
if ((a[i]-ans) % d) return -1;
t = b[i]/d; x = mul((a[i]-ans)/d, x, t);
ans += M*x; M *= t; ans %= M;
}
return ans < 0 ? ans+M : ans;
}
bsgs
// (和ex-BSGS一样,有可能需要对a,b=0特判,这里没写特判)
int bsgs(int a, int b, int mod) {
H.clear();
int m = sqrt(mod) + 1, am = qpow(a, m, mod);
for (int i = 1, t = am; i <= m; i++, t = (LL)t*am%mod)
if (!H.count(t)) H[t] = i;
int ans = -1;
for (int i = 0, t = b; i < m; i++, t = (LL)t*a%mod)
if (H.count(t)) {
int x = H[t]*m - i;
if (ans == -1 || x < ans) ans = x;
}
return ans;
}
// ex-BSGS
int exbsgs(int a, int b, int mod) {
int r = 0, t = 1, d;
while (d = gcd(a, mod), d > 1) {
if (b % d) return -1;
mod /= d, b /= d;
t = (LL)a/d*t%mod; r++;
}
int ans = bsgs(a%mod, (LL)b*inv(t, mod)%mod, mod);
return ~ans ? ans+r : -1;
}
二次剩余
// Cipolla(p必须为质数)
int a, w;
struct comp {
int x, y;
comp(int x=0, int y=0) : x(x), y(y) {}
};
comp operator * (comp a, comp b) {
return comp(((LL)a.x*b.x + (LL)a.y*b.y%mod*w)%mod, ((LL)a.x*b.y + (LL)a.y*b.x)%mod);
}
comp qpow(comp a, int b) {
comp t(1, 0);
for (; b; b >>= 1, a = a*a)
if (b & 1) t = t*a;
return t;
}
int cipo() {
if (!n) return 0;
if (mod == 2) return n;
if (qpow(n, (mod-1)/2) == mod-1) return -1;
for (;;) {
a = rand(); w = ((LL)a*a + mod - n)%mod;
if (qpow(w, (mod-1)/2) == mod-1) break;
}
return qpow(comp(a, 1), (mod+1)/2).x;
}
快速判质数(MR)
// Miller-Rabin
int test[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
bool MR(LL n) {
if (n == 1) return 0;
LL t = n-1; int k = 0;
while (!(t & 1)) k++, t >>= 1;
for (int i = 0; i < 10; i++) {
if (n == test[i]) return 1;
else if (n < test[i]) return 0;
LL a = qpow(test[i], t, n);
for (int j = 1; j <= k; j++) {
LL nxt = mul(a, a, n);
if (nxt == 1 && a != 1 && a != n-1) return 0;
a = nxt;
}
if (a != 1) return 0;
}
return 1;
}
大质数分解
// Pollard-Rho(这里求最大的质数)
LL f(LL x, LL c, LL mod) { return (mul(x, x, mod) + c) % mod; }
LL floyd(LL n) {
LL c = rand(), s = 1, t = f(s, c, n);
for (;;) {
LL s0 = s, t0 = t, tmp = 1;
for (int i = 0; i < 128; i++, s0 = f(s0, c, n), t0 = f(f(t0, c, n), c, n))
tmp = mul(tmp, abs(s0 - t0), n);
LL d = gcd(tmp, n);
if (d == 1) { s = s0, t = t0; continue; }
for (int i = 0; i < 128; i++, s = f(s, c, n), t = f(f(t, c, n), c, n))
if (d = gcd(abs(s - t), n), d != 1) return d;
}
}
LL PR(LL n) {
if (MR(n)) return n;
LL fac;
while ((fac = floyd(n)) == n) ;
return max(PR(fac), PR(n/fac));
}
Lucas 定理
// Lucas定理
int lucas(int n, int m, int p) {
if (!m) return 1;
return (LL)lucas(n/p, m/p, p) * C(n%p, m%p, p) % p;
}
// ex-Lucas
(咕咕咕)
杜教筛求 mu, phi 前缀和
int B, c, w[N], f[N]; LL g[N];
int ID(int x) { return x <= B ? x : c-n/x+1; }
void djs(int n) {
B = sqrt(n), c = 0;
for (int l = 1, r; l <= n; l = r+1)
w[++c] = r = n/(n/l);
for (int i = 1; i <= c; i++) {
int m = w[i];
if (m <= M) { f[i] = mu[m], g[i] = phi[m]; continue; }
f[i] = 1, g[i] = m * (m+1LL) / 2;
for (int l = 2, r; l <= m; l = r+1)
r = m/(m/l), f[i] -= 1LL * (r-l+1) * f[ID(m/l)], g[i] -= 1LL * (r-l+1) * g[ID(m/l)];
}
}
LCT
int ch[N][2], rev[N], val[N], sum[N], fa[N];
#define lc ch[o][0]
#define rc ch[o][1]
void pushup(int o) { sum[o] = sum[lc] ^ sum[rc] ^ val[o]; }
void pushr(int o) { rev[o] ^= 1; swap(lc, rc); }
void pushdown(int o) {
if (rev[o]) {
pushr(lc), pushr(rc); rev[o] = 0;
}
}
int get(int o) { return ch[fa[o]][1] == o ? 1 : ch[fa[o]][0] == o ? 0 : -1; }
void rotate(int o) {
int f = fa[o], d = get(o);
fa[o] = fa[f]; if (~get(f)) ch[fa[f]][get(f)] = o;
fa[ch[f][d] = ch[o][!d]] = f; fa[ch[o][!d] = f] = o; pushup(f);
}
int st[N];
void splay(int o) {
int top = 0, x = o; st[top++] = x;
while (~get(x)) x = fa[x], st[top++] = x;
while (top) pushdown(st[--top]);
for (; ~get(o); rotate(o))
if (~get(fa[o])) rotate(get(o) == get(fa[o]) ? fa[o] : o);
pushup(o);
}
void access(int x) {
for (int y = 0; x; x = fa[y = x])
splay(x), ch[x][1] = y, pushup(x);
}
void makeroot(int x) {
access(x); splay(x); pushr(x);
}
int findroot(int x) {
access(x); splay(x);
while (pushdown(x), ch[x][0]) x = ch[x][0];
return splay(x), x;
}
void split(int x, int y) {
makeroot(x), access(y), splay(y);
}
void link(int x, int y) {
if (makeroot(x), findroot(y) != x) fa[x] = y;
}
void cut(int x, int y) {
if (makeroot(x), findroot(y) == x && fa[y] == x && !ch[y][0]) ch[x][1] = fa[y] = 0, pushup(x);
}
void modify(int x, int v) {
splay(x), val[x] = v, pushup(x);
}
int qry(int x, int y) {
split(x, y); return sum[y];
}
快速沃尔什变换
void fwt_or(int *a, int n, int op) {
for (int q = 1; q < n; q <<= 1)
for (int p = 0; p < n; p += q << 1)
for (int i = 0; i < q; i++)
a[p+q+i] = op ? inc(a[p+q+i], a[p+i]) : inc(a[p+q+i], P - a[p+i]);
}
void fwt_and(int *a, int n, int op) {
for (int q = 1; q < n; q <<= 1)
for (int p = 0; p < n; p += q << 1)
for (int i = 0; i < q; i++)
a[p+i] = op ? inc(a[p+i], a[p+q+i]) : inc(a[p+i], P - a[p+q+i]);
}
void fwt_xor(int *a, int n, int op) {
for (int q = 1; q < n; q <<= 1)
for (int p = 0; p < n; p += q << 1)
for (int i = 0, t; i < q; i++) {
t = a[p+q+i], a[p+q+i] = inc(a[p+i], P - t), a[p+i] = inc(a[p+i], t);
if (!op) a[p+i] = 1LL*a[p+i]*inv2%P, a[p+q+i] = 1LL*a[p+q+i]*inv2%P;
}
}
点分治
int n, m, ask[N], ok[N];
struct Edge { int u, v, w, nxt; } e[N*2];
int edges = 0, G[N];
void adde(int u, int v, int w) {
e[edges++] = (Edge){u, v, w, G[u]};
G[u] = edges-1;
}
int rt, vis[N], sz[N], mx[N], tot;
struct Node {
int x, y;
bool operator < (const Node &rhs) const { return x < rhs.x; }
} l[N];
void dfs(int u, int f, int w, int tp) {
l[++tot] = (Node){w, tp};
for (int i = G[u], v; ~i; i = e[i].nxt)
if (v = e[i].v, v != f && !vis[v])
dfs(v, u, w + e[i].w, tp);
}
void calc(int u) {
tot = 0; l[++tot] = (Node){0, u};
for (int i = G[u], v; ~i; i = e[i].nxt)
if (v = e[i].v, !vis[v]) dfs(v, u, e[i].w, v);
sort(l+1, l+tot+1);
for (int x = 1; x <= m; x++) if (!ok[x])
for (int i = 1, j = tot; i < j; i++) {
while (i < j-1 && l[i].x + l[j].x > ask[x]) j--;
if (l[i].y != l[j].y && l[i].x + l[j].x == ask[x]) { ok[x] = 1; break; }
}
}
void getrt(int u, int f, int size) {
sz[u] = 1; mx[u] = 0;
for (int i = G[u], v; ~i; i = e[i].nxt)
if (v = e[i].v, v != f && !vis[v])
getrt(v, u, size), mx[u] = max(mx[u], sz[v]), sz[u] += sz[v];
mx[u] = max(mx[u], size-sz[u]);
if (!rt || mx[u] < mx[rt]) rt = u;
}
void solve(int u) {
vis[u] = 1; calc(u);
for (int i = G[u], v; ~i; i = e[i].nxt)
if (v = e[i].v, !vis[v]) rt = 0, getrt(v, u, sz[v]), solve(rt);
}
...
rt = 0; getrt(1, 0, n); solve(rt);
左偏树(可并堆)
int lc[N], rc[N], w[N], d[N];
int merge(int x, int y) {
if (!x || !y) return x | y;
if (w[x] > w[y] || w[x] == w[y] && x > y) swap(x, y);
rc[x] = merge(rc[x], y);
fa[rc[x]] = x;
if (d[lc[x]] < d[rc[x]]) swap(lc[x], rc[x]);
d[x] = d[rc[x]] + 1;
return x;
}
利用指针实现左偏树,实现可合并 priority_queue
template<typename T>
class PR {
private:
struct node {
T w; int d;
node *lc, *rc;
node(T w) : w(w) { lc = rc = 0; d = 1; }
} *rt;
node *_merge(node *x, node *y) {
if (!x || !y) return x ? x : y;
if (x->w > y->w) swap(x, y);
x->rc = _merge(x->rc, y);
if (x->rc && (!x->lc || x->rc->d > x->lc->d)) swap(x->lc, x->rc);
x->d = x->lc->d + 1; return x;
}
void _clear(node *x) { if (x) _clear(x->lc), _clear(x->rc), delete x; }
public:
PR() { rt = 0; }
~PR() { _clear(rt); }
bool empty() { return !rt; }
T top() { return rt->w; }
void push(T x) { rt = _merge(rt, new node(x)); }
void pop() { node *tmp = rt; rt = _merge(rt->lc, rt->rc); delete tmp; }
void merge(PR o) { rt = _merge(rt, o.rt), o.rt = 0; }
};
lagrange 插值(插多项式)
poly lagrange(int n, int *x, int *y) {
poly res(n + 1);
tmp[0] = 1;
for (int i = 1; i <= n + 1; i++) tmp[i] = 0;
for (int i = 0; i <= n; i++)
for (int j = n + 1; ~j; j--)
tmp[j] = ((j ? tmp[j - 1] : 0) - 1LL * x[i] * tmp[j] % P + P) % P;
for (int i = 0; i <= n; i++) {
int mul = 1;
for (int j = 0; j <= n; j++)
if (i != j) mul = 1LL * mul * (x[i] - x[j] + P) % P;
y[i] = 1LL * y[i] * qpow(mul, P - 2) % P;
for (int j = 0; j <= n + 1; j++) _tmp[j] = tmp[j];
for (int j = n; ~j; j--) {
_tmp[j] = (_tmp[j] + 1LL * x[i] * _tmp[j + 1]) % P;
res[j] = (res[j] + 1LL * y[i] * _tmp[j + 1]) % P;
}
}
return fix(res), res;
}
字符串
Lyndon 分解
#include <bits/stdc++.h>
const int N = 5e6 + 5;
int n; char s[N];
int lyndon(char *s) {
n = strlen(s + 1);
int ans = 0;
for (int i = 1; i <= n; ) {
int j = i, k = i + 1;
while (k <= n && s[k] >= s[j]) {
if (s[k] > s[j]) j = i; else j++;
k++;
}
while (i <= j) {
i += k - j;
ans ^= i - 1;
}
}
return ans;
}
int main() {
scanf("%s", s + 1);
printf("%d", lyndon(s));
return 0;
}
KMP
void getfail() {
fail[1] = 0;
for (int i = 2, j = 0; i <= m; i++) {
while (j && t[i] != t[j + 1]) j = fail[j];
fail[i] = t[i] == t[j + 1] ? ++j : 0;
}
}
int kmp() {
int ans = 0;
for (int i = 1, j = 0; i <= n; i++) {
while (j && s[i] != t[j + 1]) j = fail[j];
j = s[i] == t[j + 1] ? j + 1 : 0;
if (j == m) ans++;
}
return ans;
}
Z 函数(扩展 KMP)
void getex() {
a[1] = m;
for (int i = 2, l = 1, r = 1; i <= m; i++) {
a[i] = i <= r ? std::min(a[i - l + 1], r - i) : 0;
while (t[i + a[i]] == t[a[i] + 1]) a[i]++;
if (i + a[i] > r) l = i, r = i + a[i];
}
}
void exkmp() {
for (int i = 1, l = 0, r = 0; i <= n; i++) {
b[i] = i <= r ? std::min(a[i - l + 1], r - i) : 0;
while (i + b[i] <= n && s[i + b[i]] == t[b[i] + 1]) b[i]++; // 必须要判断串长 <= n
if (i + b[i] > r) l = i, r = i + b[i];
}
}
AC 自动机
void build() {
std::queue<int> Q;
for (int i = 0; i < M; i++)
if (ch[1][i]) fail[ch[1][i]] = 1, Q.push(ch[1][i]);
else ch[1][i] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = 0; i < M; i++)
if (ch[u][i]) fail[ch[u][i]] = ch[fail[u]][i], Q.push(ch[u][i]);
else ch[u][i] = ch[fail[u]][i];
}
for (int i = 2; i <= tot; i++) G[fail[i]].pb(i);
}
后缀数组
void build(int n, char *s) {
static int c[N], t[N * 2], t2[N * 2], *x = t, *y = t2;
int m = 'z';
std::fill(c + 1, c + m + 1, 0);
for (int i = 1; i <= n; i++) c[x[i] = s[i]]++;
std::partial_sum(c + 1, c + m + 1, c + 1);
for (int i = n; i; i--) sa[c[x[i]]--] = i;
for (int k = 1; k < n; k <<= 1) {
int p = 0;
for (int i = n; i > n - k; i--) y[++p] = i;
// assert(p == k);
for (int i = 1; i <= n; i++)
if (sa[i] > k) y[++p] = sa[i] - k;
std::fill(c + 1, c + m + 1, 0);
for (int i = 1; i <= n; i++) c[x[y[i]]]++;
std::partial_sum(c + 1, c + m + 1, c + 1);
for (int i = n; i; i--) sa[c[x[y[i]]]--] = y[i];
std::swap(x, y); x[sa[1]] = p = 1;
for (int i = 2; i <= n; i++) {
if (y[sa[i]] != y[sa[i - 1]] || y[sa[i] + k] != y[sa[i - 1] + k]) p++;
x[sa[i]] = p;
}
if ((m = p) == n) return;
}
}
SAM
void extend(int x) {
int p = last, cur = ++tot;
len[cur] = len[p] + 1;
for (; p && !ch[p][x]; p = fa[p])
ch[p][x] = cur;
if (!p) fa[cur] = 1;
else {
int q = ch[p][x];
if (len[p] + 1 == len[q]) fa[cur] = q;
else {
int cpy = ++tot;
std::copy(ch[q], ch[q] + M, ch[cpy]);
len[cpy] = len[p] + 1;
fa[cpy] = fa[q], fa[q] = fa[cur] = cpy;
for (; p && ch[p][x] == q; p = fa[p])
ch[p][x] = cpy;
}
}
val[cur] = 1;
last = cur;
}