『考点列表』

Part1 数学相关

1 线性代数

矩阵快速幂

点击查看代码
struct MATR{
	int a[N][N], r, c;
	MATR() {memset(a, 0, sizeof(a));}
	void init() {
		for (int i = 1; i <= r; ++i) a[i][i] = 1;
	}
	MATR operator *(const MATR &x) const {
		MATR ret;
		ret.r = r, ret.c = x.c;
		for (int i = 1; i <= r; ++i)
			for (int k = 1; k <= c; ++k)
				if (a[i][k]) for (int j = 1; j <= x.c; ++j)
					(ret.a[i][j] += 1ll*a[i][k]*x.a[k][j]%MOD) %= MOD;
		return ret;
	}
};

MATR powMA(MATR x, long long y) {
	MATR ret;
	ret.r = x.r, ret.c = x.c;
	ret.init();
	while (y) {
		if (y&1) ret = ret*x;
		x = x*x, y >>= 1;
	} return ret;
}

2 数论

裴蜀定理

\[ax+by=c,x\in Z^*,y\in Z^* \Leftrightarrow gcd(a,b)|c \]

扩展欧几里得算法

点击查看代码
LL exgcd(LL a, LL b, LL &x, LL &y) {
	if (!b) {
		x = 1, y = 0;
		return a;
	}
	LL tmp1 = exgcd(b, a%b, x, y), tmp2;
	tmp2 = x, x = y, y = tmp2-(a/b)*y;
	return tmp1;
}

3 计数类

Lucas定理

点击查看代码
int luc(int x, int y) {
	if (x < y) return 0;
	if (!x || !y || x == y) return 1;
	return 1ll*CC(x%Mod, y%Mod)*luc(x/Mod, y/Mod)%Mod;
}

Part2 数据结构

1 线段树

标准型(加乘)

点击查看代码
int sum[N<<2], taga[N<<2], tagm[N<<2], a[N];
void pushup(int &x, int y, int z) {x = plu(y, z);}
void build(int now, int L, int R) {
	tagm[now] = 1;
	if (L == R) {
		sum[now] = a[L];
		return ;
	}
	segc;
	build(lc, L, mid), build(rc, mid+1, R);
	pushup(sum[now], sum[lc], sum[rc]);
}
void pushdown(int now, int L, int R) {
	segc;
	sum[lc] = plu(mul(sum[lc], tagm[now]), mul(taga[now], mid-L+1));
	sum[rc] = plu(mul(sum[rc], tagm[now]), mul(taga[now], R-mid));
	tagm[lc] = mul(tagm[lc], tagm[now]);
	tagm[rc] = mul(tagm[rc], tagm[now]);
	taga[lc] = plu(mul(taga[lc], tagm[now]), taga[now]);
	taga[rc] = plu(mul(taga[rc], tagm[now]), taga[now]);
	taga[now] = 0, tagm[now] = 1;
}
void modifya(int now, int L, int R, int ql, int qr, ll val) {
	if (ql <= L && R <= qr) {
		sum[now] += val*(R-L+1);
		taga[now] += val;
		return ;
	}
	segc;
	pushdown(now, L, R);
	if (ql <= mid) modifya(lc, L, mid, ql, qr, val);
	if (qr > mid) modifya(rc, mid+1, R, ql, qr, val);
	pushup(sum[now], sum[lc], sum[rc]);
}
void modifym(int now, int L, int R, int ql, int qr, ll val) {
	if (ql <= L && R <= qr) {
		sum[now] = mul(sum[now], val);
		taga[now] = mul(taga[now], val);
		tagm[now] = mul(tagm[now], val);
		return ;
	}
	segc;
	pushdown(now, L, R);
	if (ql <= mid) modifym(lc, L, mid, ql, qr, val);
	if (qr > mid) modifym(rc, mid+1, R, ql, qr, val);
	pushup(sum[now], sum[lc], sum[rc]);
}
ll ask(int now, int L, int R, int ql, int qr) {
	if (ql <= L && R <= qr) return sum[now];
	segc; int ret = 0;
	pushdown(now, L, R);
	if (ql <= mid) ret = plu(ret, ask(lc, L, mid, ql, qr));
	if (qr > mid) ret = plu(ret, ask(rc, mid+1, R, ql, qr));
	return ret;
}

兔队线段树

点击查看代码
int cntr[N<<2];
double mx[N<<2];
int calc(int now, int L, int R, double Lim) {
	if (L == R) return mx[now] > Lim;
	segc;
	if (mx[lc] > Lim) return calc(lc, L, mid, Lim)+cntr[now];
	else return 0+calc(rc, mid+1, R, Lim);
}
void pushup(int now, int L, int R) {
	segc;
	mx[now] = max(mx[lc], mx[rc]);
	cntr[now] = calc(rc, mid+1, R, mx[lc]);
}
void update(int now, int L, int R, int pos, double val) {
	if (L == R) {
		mx[now] = val;
		return ;
	}
	segc;
	if (pos <= mid) update(lc, L, mid, pos, val);
	else update(rc, mid+1, R, pos, val);
	pushup(now, L, R);
}

2 ST表(维护任何可并性信息)

点击查看代码
void buildst() {
	rep (i, 2, n) lg[i] = lg[i>>1]+1;
	rep (j, 1, lg[n]) rep (i, 1, n-(1<<j)+1) st[i][j] = max(st[i][j-1], st[i+(1<<(j-1))][j-1]);
}

inline int queryst(int L, int R) {
	int dep = lg[R-L+1];
	return max(st[L][dep], st[R-(1<<dep)+1][dep]);
}

Part3 字符串题

1 KMP

点击查看代码
int n, m, tpp[N];
char str1[N], str2[N];

	for (int i = 1, j = 0; i < m; ++i) {
		while (j > 0 && str2[j+1] != str2[i+1]) j = tpp[j];
		if (str2[i+1] == str2[j+1]) ++j;
		tpp[i+1] = j;
	}
	for (int i = 0, j = 0; i < n; ++i) {
		while (j > 0 && str2[j+1] != str1[i+1]) j = tpp[j];
		if (str1[i+1] == str2[j+1]) ++j;
		if (j == m) {
			printf("%d\n", i+1-m+1);
			j = tpp[j];
		}
	}

2 Manacher

点击查看代码
	scanf("%s", str+1);
	int n = strlen(str+1);
	rep (i, 1, n) a[2*i-1] = '@', a[2*i] = str[i];
	a[2*n+1] = '@', n = 2*n+1;
	rep (i, 1, n) R[i] = 0;
	R[1] = 1;
	int rr = 1, ctr = 1, ans = 0;
	rep (i, 1, n) {
		if (i <= rr) R[i] = min(rr-i+1, R[2*ctr-i]);
		while (i-R[i] >= 0 && i+R[i] <= n && a[i-R[i]] == a[i+R[i]]) ++R[i];
		if (i+R[i]-1 > rr) rr = i+R[i]-1, ctr = i;
	}

3 SAM

  一定一定要注意两倍空间啊!

点击查看代码
struct Node {
	int ch[26];
	int len, fa;
}a[N];
int pre = 1, cnt = 1;
long long siz[N];
void add(int x) {
	int p = pre, np = pre = ++cnt;
	a[np].len = a[p].len+1; siz[np] = 1;
	for (; p && !a[p].ch[x]; p = a[p].fa) a[p].ch[x] = np;
	if (!p) a[np].fa = 1;
	else {
		int q = a[p].ch[x];
		if (a[q].len == a[p].len+1) a[np].fa = q;
		else {
			int nq = ++cnt; a[nq] = a[q];
			a[nq].len = a[p].len+1;
			a[q].fa = a[np].fa = nq;
			for (; p && a[p].ch[x] == q; p = a[p].fa) a[p].ch[x] = nq;
		}
	}
}

Part4 图论相关

1 并查集

点击查看代码
int fa[N], tot[N];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
int merge(int x, int y) {
	x = find(x), y = find(y);
	if (x == y) return ;
	fa[x] = y, tot[y] += tot[x];
}

2 树上问题

LCA(树上倍增)

点击查看代码
int lg[N], dep[N], fa[N][20];
void init_lg() {rep (i, 1, n) lg[i] = lg[i-1]+(1<<lg[i-1] == i);}
void dfs(int x, int par) {
	fa[x][0] = par; dep[x] = dep[par]+1;
	rep (i, 1, lg[dep[x]]) fa[x][i] = fa[fa[x][i-1]][i-1];
	for (auto y:G[x]) if (y != par) dfs(y, x);
}
int LCA(int x, int y) {
	if(dep[x] < dep[y]) swap(x, y);
	while (dep[x] > dep[y]) x = fa[x][lg[dep[x]-dep[y]]-1];
	if (x == y) return x;
	rep (i, lg[dep[x]]-1, 0) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}

树链剖分

点击查看代码
void update1(int x, int y, int w) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		update(1, 1, n, id[top[x]], id[x], w);
		x = fa[top[x]];
	}
	if (dep[x] > dep[y]) swap(x, y);
	update(1, 1, n, id[x], id[y], w);
}

void update2(int x, int w) {
	update(1, 1, n, id[x], id[x]+siz[x]-1, w);
}

LL query1(int x, int y) {
	LL ret = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		(ret += query(1, 1, n, id[top[x]], id[x])) %= mod;
		x = fa[top[x]];
	}
	if (dep[x] > dep[y]) swap(x, y);
	(ret += query(1, 1, n, id[x], id[y])) %= mod;
	return ret;
}

LL query2(int x) {
	return query(1, 1, n, id[x], id[x]+siz[x]-1);
}

void dfs1(int now, int pre, int depp) {
	dep[now] = depp;
	fa[now] = pre;
	siz[now] = 1;
	int mxs = -1;
	for (auto y:G[now]) {
		if (y == pre) continue ;
		dfs1(y, now, depp+1);
		siz[now] += siz[y];
		if (siz[y] > mxs) son[now] = y, mxs = siz[y];
	}
}

void dfs2(int now, int topf) {
	id[now] = ++cntn;
	val[cntn] = a[now];
	top[now] = topf;
	if (!son[now]) return ;
	dfs2(son[now], topf);
	for (auto y:G[now]) {
		if (y == fa[now] || y == son[now]) continue ;
		dfs2(y, y);
	}
}

3 最短路

Dijkstra

点击查看代码
int dis[N];
bool vis[N];
void dij(int S) {
	for (int i = 1; i <= n; ++i) dis[i] = Inf;
	dis[S] = 0;
	priority_queue<pair<int, int> > q;
	q.push(mp(0, S));
	while (!q.empty()) {
		int x = q.top().second; q.pop();
		if (vis[x]) continue ;
		vis[x] = true;
		for (int i = head[x]; i; i = e[i].next) {
			int y = e[i].to;
			if (dis[y] > dis[x]+e[i].w) {
				dis[y] = dis[x]+e[i].w;
				q.push(mp(-dis[y], y));
			}
		}
	}
}

差分约束(SPFA)

点击查看代码
struct BLCK{
	int to, next, w;
}e[N+M];									//注意超级原点连的边 
int head[N], ecnt;
void addE(int u, int v, int w) {
	e[++ecnt].next = head[u], head[u] = ecnt;
	e[ecnt].to = v, e[ecnt].w = w;
}

int dis[N], tot[N];
bool vis[N];
bool spfa(int S) {
	queue<int> q;
	for (int i = 1; i <= n; ++i) dis[i] = INF;
	dis[S] = 0, vis[S] = 1;
	q.push(S);
	while (!q.empty()) {
		int x = q.front(); q.pop(); vis[x] = 0;
		for (int i = head[x]; i; i = e[i].next) {
			int y = e[i].to;
			if (dis[x]+e[i].w < dis[y]) {
				dis[y] = dis[x]+e[i].w;
				tot[y] = tot[x]+1;
				if (tot[y] >= n+1) return false;
				if (!vis[y]) vis[y] = 1, q.push(y);
			}
		}
	} return true;
}
void cfys() {
	for (int i = 1; i <= n; ++i) addE(0, i, 0);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d%d", &v, &u, &w);
		addE(u, v, w);
	}
	if (!spfa(0)) printf("NO\n");
	else for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
}

4 最小生成树

Kruskal

点击查看代码
void kruskal() {
	for (int i = 1; i <= n; ++i) fa[i] = i;
	sort(e+1, e+1+m, cmp);
	for (int i = 1; i <= m && cnt < n-1; ++i) {
		int fu = find(e[i].u), fv = find(e[i].v);
		if (fu == fv) continue ;
		++cnt, ans += e[i].w;
		fa[fu] = fv;
	}
}

Kruskal重构树

点击查看代码
int f[N<<1];
void kru() {
	sort(e+1, e+1+m, cmp);
	for (int i = 1; i <= 2*n; ++i) fa[i] = i;
	int ncnt = n;
	for (int i = 1; i <= m; ++i) {
		int fu = find(e[i].u), fv = find(e[i].to);
		if (fu == fv) continue ;
		fa[fu] = fa[fv] = ++ncnt;
		add(ncnt, fu), add(fu, ncnt);
		add(ncnt, fv), add(fv, ncnt);
		val[cnt] = e[i].w;
	}
}

5 图连通性

割点

点击查看代码
int ccnt, buc[N], dfn[N], low[N], rt, dn;
void dfs(int now) {
	dfn[now] = low[now] = ++dn;
	int scnt = 0;
	for (int i = head[now]; i; i = e[i].next) {
		int y = e[i].to;
		if (!dfn[y]) {
			++scnt, dfs(y), low[now] = min(low[now], low[y]);
			if (low[y] >= dfn[now] && now != rt) ccnt += !buc[now], buc[now] = 1;
		} else low[now] = min(low[now], dfn[y]);
	}
	if (scnt >= 2 && now == rt) ccnt += !buc[now], buc[now] = 1;
}
void getbuc() {
	for (int i = 1; i <= n; ++i) if (!dfn[i]) rt = i, dfs(i);
}

强连通分量

点击查看代码
int n, m, col[N], cntc, dfn[N], low[N], vis[N], stc[N], top, dn;
vector<int> G[N], GG[N];
void tarjan(int now) {
	vis[now] = 1, dfn[now] = low[now] = ++dn, stc[++top] = now;
	for (auto y:G[now]) {
		if (!dfn[y]) tarjan(y), low[now] = min(low[now], low[y]);
		else if(vis[y]) low[now] = min(low[now], dfn[y]);
	}
	if (dfn[now] == low[now]) {
		col[now] = ++cntc;
		while (stc[top] != now) col[stc[top]] = cntc, vis[stc[top--]] = 0;
		vis[now] = 0, --top;
	}
}
int a[N], val[N];
void shr() {

	for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
	for (int i = 1; i <= n; ++i) {
		val[col[i]] += a[i];
		for (auto y:G[i])
			if (col[i] != col[y]) GG[col[i]].emplace_back(col[y]);
	}
}

6 网络流

最大流(Dinic)

点击查看代码
int dis[N], cur[N];
bool bfs() {
	for (int i = 1; i <= cntn; ++i) dis[i] = INF, cur[i] = head[i];
	queue<int> q;
	q.push(S);
	dis[S] = 0;
	while (!q.empty()) {
		int x = q.front(); q.pop();
		for (int i = head[x]; i; i = e[i].next) {
			int y = e[i].to;
			if (e[i].w && dis[y] == INF) {
				q.push(y);
				dis[y] = dis[x]+1;
				if (y == T) return true;
			}
		}
	} return false;
}
int dfs(int x, int flow) {
	if (!flow || x == T) return flow;
	int used = 0;
	for (int &i = cur[x]; i && used < flow; i = e[i].next) {
		int y = e[i].to;
		if (dis[y] != dis[x]+1) continue ;
		int tmp = dfs(y, min(flow-used, e[i].w));
		if (tmp) {
			e[i].w -= tmp; e[i^1].w += tmp;
			used += tmp;
		}
	} return used;
}
void dinic(int &ans) {while (bfs()) ans += dfs(S, INF);}

最小费用费用流(SPFA+Dinic)

点击查看代码
int dis[N], cur[N];
bool vis[N];
bool spfa() {
	for (int i = 1; i <= cntn; ++i) dis[i] = INF, cur[i] = head[i];
	queue<int> q;
	q.push(S);
	dis[S] = 0;
	vis[S] = 1;
	while (!q.empty()) {
		int x = q.front(); q.pop(), vis[x] = 0;
		for (int i = head[x]; i; i = e[i].next) {
			int y = e[i].to;
			if (dis[y] > dis[x]+e[i].c && e[i].w) {
				dis[y] = dis[x]+e[i].c;
				if (!vis[y]) {
					q.push(y);
					vis[y] = 1;
				}
			}
		}
	} return dis[T] != INF;
}

int dfs(int x, int flow) {
	if (x == T || !flow) return flow;
	int used = 0;
	vis[x] = 1;
	for (int &i = cur[x]; i && used < flow; i = e[i].next) {
		int y = e[i].to;
		if (dis[y] != dis[x]+e[i].c || vis[y]) continue ;
		int tmp = dfs(y, min(flow-used, e[i].w));
		if (tmp) {
			e[i].w -= tmp, e[i^1].w += tmp;
			used += tmp;
			totc += tmp*e[i].c;
		}
	}
	vis[x] = 0;
	return used;
}

int MCCF(int x, int y) {
	int ans = 0; S = x, T = y, totc = 0;
	while (spfa()) ans += dfs(S, INF);
	return totc;
}

Ex 码头

1 define & 常量

点击查看代码
#define mp make_pair
#define vi vector<int>
#define eb emplace_back
#define pli pair<LL, int>
#define segc int mid = L+R>>1, lc = now<<1, rc = lc|1
const int N = 1e5+5, MOD = 998244353, INF = 1e9;
typedef long long LL;

2 快速I/O

点击查看代码
inline int read() {
	int x = 0, f = 1; char ch = 0;
	while (!isdigit(ch)) {ch = getchar();if (ch == '-') f = -1;}
	while (isdigit(ch)) x = (x<<3)+(x<<1)+(ch^48), ch = getchar();
	return f*x;
}
inline void put(int x) {  
	int num=0; char c[15];
	if (x == 0) {puts("0"); return ;}
	if (x < 0) putchar('-'),x = -x;
	while (x) c[++num] = (x%10)+48, x /= 10;
	while (num) putchar(c[num--]);
	putchar('\n'); 
}

3 封装加乘幂

点击查看代码
int plu(int x, int y) {return x += y, x >= MOD && (x -= MOD), x;}
void plut(int &x, int y) {x += y, x >= MOD && (x -= MOD);}
int mul(int x, int y) {return 1ll*x*y%MOD;}
int powM(int x, int y = MOD-2) {
	int ret = 1;
	while (y) {
		if (y&1) ret = mul(ret, x);
		x = mul(x, x), y >>= 1;
	} return ret;
}

4 组合数

点击查看代码
int fac[N], ifac[N];
int CC(int x, int y) {
	if (x < y) return 0;
	return mul(mul(fac[x], ifac[y]), ifac[x-y]);
}
void init_fac() {
	for (int i = fac[0] = 1; i <= N-5; ++i) fac[i] = mul(fac[i-1], i);
	ifac[N-5] = powM(fac[N-5]);
	for (int i = N-6; ~i; --i) ifac[i] = mul(ifac[i+1], i+1);
}

5 总集

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define mp make_pair
#define vi vector<int>
#define eb emplace_back
#define pli pair<LL, int>
#define fi first
#define se second
#define rep(rp,a,b) for(int rp=a;rp<=b;++rp)
#define per(bl,a,b) for(int bl=a;bl>=b;--bl)
#define segc int mid = L+R>>1, lc = now<<1, rc = lc|1
const int N = 1e5+5, MOD = 998244353, INF = 1e9;
inline int read() {
	int x = 0, f = 1; char ch = 0;
	while (!isdigit(ch)) {ch = getchar(); if (ch == '-') f = -1;}
	while (isdigit(ch)) x = (x<<3)+(x<<1)+(ch^48), ch = getchar();
	return f*x;
}
inline void put(int x) {  
	int num=0; char c[15];
	if (x == 0) {puts("0"); return ;}
	if (x < 0) putchar('-'), x = -x;
	while (x) c[++num] = (x%10)+48, x /= 10;
	while (num) putchar(c[num--]);
	putchar('\n'); 
}
inline int plu(int x, int y) {return x += y, x >= MOD && (x -= MOD), x;}
inline int mul(int x, int y) {return 1ll*x*y%MOD;}
int powM(int x, int y = MOD-2) {
	int ret = 1;
	while (y) {
		if (y&1) ret = mul(ret, x);
		x = mul(x, x), y >>= 1;
	} return ret;
}
int fac[N], ifac[N], pw2[N];
int C(int x, int y) {
	if (x < y) return 0;
	return mul(mul(fac[x], ifac[y]), ifac[x-y]);
}
void init() {
	fac[0] = pw2[0] = 1;
	rep (i, 1, N-5) fac[i] = mul(fac[i-1], i);
	ifac[N-5] = powM(fac[N-5]);
	per (i, N-6, 0) ifac[i] = mul(ifac[i+1], i+1);
	rep (i, 1, N-5) pw2[i] = pw2[i-1]*2%MOD;
}

// ---------- templates above ----------
posted @ 2023-10-14 11:40  Black_Crow  阅读(32)  评论(0编辑  收藏  举报