My Code

突然发现曾经写的一些模版还是上锁的,直接解锁提供给大家了

数论模板

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;
}
posted @ 2021-01-20 20:04  AC-Evil  阅读(17)  评论(0)    收藏  举报