CSP考前复习

CSP考前复习

前言

因为loceaner太菜了,他什么东西都不会
所以他打算学一个东西就记录一下
不过因为他很菜,所以他不会写原理……
而且,他希望在2019CSP之前不会断更
就酱紫,就是写给他自己的……因为他太菜了

基础算法

小技巧

[sum_{i = 0}^{x}C(x, i)* C(y, i) = C(x + y, x) ]

使用负数下标

如何使用负数下标呢?
让数组前面有东西

int y[100];
int *z = y + 50;

这样的话调用(z[-50])就变成了调用(y[0])

z[-50] = y[0];

然后这样就可以实现调用啦~

其实还有一个更暴力的方法:用(map)

(map)(log n)(map)
(unordered\_map)(O(1))(map)(到(c++11)才会有)

二维前缀和

//知识点:二维前缀和
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 1000;

int n, m;
int a[N][N], b[N][N];

int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			a[i][j] = read();
			b[i][j] = a[i][j] + b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
		}
	}
	for(int i, u1, v1, u2, v2; i <= m; i++) {
		u1 = read(), v1 = read(), u2 = read(), v2 = read();
		cout << b[u2][v2] - b[u1 - 1][v2] - b[u2][v1 - 1] + b[u1 - 1][v1 - 1] << '
';
	} 
	return 0;
}

三分法

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const double eps = 1e-6;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n;
double l, r, a[A];


double f(double x) {
	double ans = 0;
	for(int i = 1; i <= n + 1; i++) ans = ans * x + a[i];
	return ans;
}

int main() {
	n = read(); scanf("%lf%lf", &l, &r);
	for(int i = 1; i <= n + 1; i++) scanf("%lf", &a[i]);
	while(r - l >= eps) {
		double qwq = (r - l) / 3.0, lmid = l + qwq, rmid = r - qwq;
		if(f(lmid) > f(rmid)) r = rmid; 
		else l = lmid;
	}
	printf("%.5lf", l);
	return 0;
}

二维差分

//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 1e3 + 11;

int n, m, a[N][N];

int main() {
	n = read(), m = read();
	for(int i = 1, u1, u2, v1, v2; i <= m; i++) {
		u1 = read(), v1 = read(), u2 = read(), v2 = read();
		a[u1][v1] += 1;
		a[u2 + 1][v2 + 1] += 1;
		a[u2 + 1][v1] -= 1;
		a[u1][v2 + 1] -= 1;
	}
	//C[x1][y1] += x ,  C[x2 + 1][y2 + 1] += x ,  C[x1][y2 + 1] -= x , C[x2 + 1][y1] -= x;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];;
		} 
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			cout << a[i][j] << ' ';
		}
		cout << '
';
	}
	return 0;
}

归并排序

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

int n, m, a[A], b[A];

void solve(int l, int r) {
	if(l == r) return;
	int mid = (l + r) >> 1;
	solve(l, mid), solve(mid + 1, r);
	int i = l, j = mid + 1, k = l;
	while(i <= mid && j <= r) {
		if(a[i] <= a[j]) b[k++] = a[i++];
		else b[k++] = a[j++];
	}
	while(i <= mid) b[k++] = a[i++]; 
	while(j <= r) b[k++] = a[j++];
	for(int i = l; i <= r; i++) a[i] = b[i];
}

int main() {
//	freopen("a.in", "r", stdin);
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	solve(1, n);
	for(int i = 1; i <= n; i++) cout << a[i] << ' ';
	return 0;
}

排序不等式

给定3组数(a, b, c)
(a[1])~(a[n]),(b[1])~(b[n]),(c[1])~(c[n])
其中(c[1])~(c[n])(b[1])~(b[n])的乱序排列
(a[1]*b[n]+a[2]*b[n-1]+...<=a[1]*c[1]+a[2]*c[2]+...<=a[1]*b[1]+a[2]*b[2]+...)
即:逆序和 <= 乱序和 <= 正序和

关于(long long)

在日常的题目中,一定要看好数据范围,如果会爆(int)的话,不要忘记开(long long)(无数次被坑!!)

高精度模板

最让人烦的就是高精度了,某些题并不难,但是要写高精。。烦(color{white}{(ps:板子来自lfd)})

namespace BigInteger {
	struct Big_integer {
		int d[10005], len;
		void clean() {while(len > 1 and !d[len - 1]) len--;}
		Big_integer() {memset(d, 0, sizeof d);len = 1;}
		Big_integer(int num) {*this = num;}
		Big_integer operator = (const char* num) {
			memset(d, 0, sizeof d);
			len = strlen(num);
			for (int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
			clean();
			return *this;
		}
		Big_integer operator = (int num) {
			char s[10005];
			sprintf(s, "%d", num);
			*this = s;
			return *this;
		}
		Big_integer operator * (const Big_integer &b) const {
			int i, j;
			Big_integer c;
			c.len = len + b.len;
			for (j = 0; j < b.len; j++)
				for (i = 0; i < len; i++)
					c.d[i + j] += d[i] * b.d[j];
			for (i = 0; i < c.len - 1; i++) c.d[i + 1] += c.d[i] / 10, c.d[i] %= 10;
			c.clean();
			return c;
		}
		Big_integer operator / (const int &b) {
			int i, j, a = 0;
			Big_integer c = *this;
			for (i = len - 1; i >= 0; i--) {
				a = a * 10 + d[i];
				for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
				c.d[i] = j;
				a = a - b * j;
			}
			c.clean();
			return c;
		}
		bool operator < (const Big_integer &b) const {
			if (len != b.len) return len < b.len;
			for (int i = len - 1; i >= 0; i--)
				if (d[i] != b.d[i])
					return d[i] < b.d[i];
			return false;
		}
		string str() const {
			char s[10005];
			for (int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
			return s;
		}
	};
	istream& operator >> (istream& in, Big_integer &x) {
		string s;
		in >> s;
		x = s.c_str();
		return in;
	}
	ostream& operator << (ostream& out, const Big_integer &x) {
		out << x.str();
		return out;
	}
}
using namespace BigInteger;

数据结构

树状数组

单点修改,区间查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, c[B];

void update(int x, int k) {
	while(x <= n) {
		c[x] += k;
		x += lowbit(x);
	}
}

int query(int x) {
	int ans = 0;
	while(x) {
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}

int main() {
	n = read(), m = read();
	for(int i = 1, a; i <= n; i++) {
		a = read();
		update(i, a);
	}
	while(m--) {
		int opt = read(), x = read(), y = read();
		if(opt == 1) update(x, y);
		else cout << query(y) - query(x - 1) << '
';
	}
	return 0;
}

区间修改,单点查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, c[B], a[B];

void update(int x, int k) {
	while(x <= n) {
		c[x] += k;
		x += lowbit(x);
	}
}

int query(int x) {
	int ans = 0;
	while(x) {
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}

int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	while(m--) {
		int opt = read(), x = read(), y, k;
		if(opt == 1) y = read(), k = read(), update(x, k), update(y + 1, -k);
		else cout << a[x] + query(x) << '
';
	}
	return 0;
}

线段树

区间修改,区间查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m;

namespace Seg {
	#define lson rt << 1
	#define rson rt << 1 | 1
	struct tree {
		int l, r, w, lazy;
	} t[A << 2];
	inline void pushup(int rt) { t[rt].w = t[lson].w + t[rson].w; }
	inline void pushdown(int rt) {
		t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy;
		t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy;
		t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy;
		t[rt].lazy = 0;
	}
	void build(int rt, int l, int r) {
		t[rt].l = l, t[rt].r = r;
		if(l == r) { t[rt].w = read(); return; }
		int mid = (l + r) >> 1;
		build(lson, l, mid), build(rson, mid + 1, r);
		pushup(rt); return;
	}
	void update(int rt, int l, int r, int val) {
		if(l <= t[rt].l && t[rt].r <= r) {
			t[rt].lazy += val;
			t[rt].w += (t[rt].r - t[rt].l + 1) * val;
			return;
		}
		if(t[rt].lazy) pushdown(rt); 
		int mid = (t[rt].l + t[rt].r) >> 1;
		if(l <= mid) update(lson, l, r, val);
		if(r > mid) update(rson, l, r, val);
		pushup(rt); return;
	}
	int query(int rt, int l, int r) {
		if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w; }
		if(t[rt].lazy) pushdown(rt); 
		int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
		if(l <= mid) ans += query(lson, l, r);
		if(r > mid) ans += query(rson, l, r);
		return ans;
	}
}

signed main() {
	n = read(), m = read();
	Seg::build(1, 1, n);
	while(m--) {
		int opt = read(), x = read(), y = read(), k;
		if(opt == 1) k = read(), Seg::update(1, x, y, k);
		else cout << Seg::query(1, x, y) << '
';
	}
	return 0;
}

区间加,区间乘,区间求和

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, mod;

namespace Seg {
	#define lson rt << 1
	#define rson rt << 1 | 1
	struct tre {
		int l, r, w, lazy1, lazy2;
	} t[A << 2];
	inline void pushup(int rt) {
		t[rt].w = (t[lson].w + t[rson].w) % mod;
	}
	inline void tag1(int rt, int val) {
		t[rt].lazy1 *= val, t[rt].lazy2 *= val;
		t[rt].lazy1 %= mod, t[rt].lazy2 %= mod;		
		t[rt].w *= val, t[rt].w %= mod;
	}
	inline void tag2(int rt, int val) {
		t[rt].lazy2 += val; t[rt].lazy2 %= mod;
		t[rt].w += (t[rt].r - t[rt].l + 1) * val, t[rt].w %= mod;
	}
	inline void pushdown(int rt) {
		if(t[rt].lazy1 != 1) {
			tag1(lson, t[rt].lazy1);
			tag1(rson, t[rt].lazy1);
			t[rt].lazy1 = 1;
		}
		if(t[rt].lazy2) {
			tag2(lson, t[rt].lazy2);
			tag2(rson, t[rt].lazy2);
			t[rt].lazy2 = 0;
		}
	}
	inline void build(int rt, int l, int r) {
		t[rt].l = l, t[rt].r = r, t[rt].lazy1 = 1, t[rt].lazy2 = 0;
		if(l == r) { t[rt].w = read(); return; }
		int mid = (l + r) >> 1;
		build(lson, l, mid), build(rson, mid + 1, r);
		pushup(rt); return;
	}
	inline void mul(int rt, int l, int r, int val) {
		if(l <= t[rt].l && t[rt].r <= r) return tag1(rt, val);
		pushdown(rt);
		int mid = (t[rt].l + t[rt].r) >> 1;
		if(l <= mid) mul(lson, l, r, val);
		if(r > mid) mul(rson, l, r, val);
		pushup(rt); return;
	}
	inline void update(int rt, int l, int r, int val) {
		if(l <= t[rt].l && t[rt].r <= r) return tag2(rt, val);
		pushdown(rt);
		int mid = (t[rt].l + t[rt].r) >> 1;
		if(l <= mid) update(lson, l, r, val);
		if(r > mid) update(rson, l, r, val);
		pushup(rt); return;
	}
	inline int query(int rt, int l, int r) {
		if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w % mod; }
		pushdown(rt);
		int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
		if(l <= mid) ans += query(lson, l, r), ans %= mod;
		if(r > mid) ans += query(rson, l, r), ans %= mod;
		return ans % mod;
	}
}

signed main() {
	n = read(), m = read(), mod = read();
	Seg::build(1, 1, n);
	while(m--) {
		int opt = read(), x = read(), y = read(), k;
		if(opt == 1) k = read() % mod, Seg::mul(1, x, y, k);
		else if(opt == 2) k = read() % mod, Seg::update(1, x, y, k);
		else cout << Seg::query(1, x, y) % mod << '
';
	}
	return 0;
}

单调栈

for(int i = 0; i < T.size(); i++){
  while(! stk.empty() && stk.top() > T[i]){
    ​stk.pop();
  }
  stk.push(A[i]);
}

单调队列

上经典的滑动窗口问题

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxn 1000100
using namespace std;
int q[maxn], a[maxn];
int n, k;
void getmin() {
	int head = 0, tail = 0;
	for (int i = 1; i < k; i++) {
		while (head <= tail && a[q[tail]] >= a[i]) tail--;
		q[++tail] = i;
	}
	for (int i = k; i <= n; i++) {
		while (head <= tail && a[q[tail]] >= a[i]) tail--;
		q[++tail] = i;
		while (q[head] <= i - k) head++;
		printf("%d ", a[q[head]]);
	}
}

void getmax() {
	int head = 0, tail = 0;
	for (int i = 1; i < k; i++) {
		while (head <= tail && a[q[tail]] <= a[i]) tail--;
		q[++tail] = i;
	}
	for (int i = k; i <= n; i++) {
		while (head <= tail && a[q[tail]] <= a[i]) tail--;
		q[++tail] = i;
		while (q[head] <= i - k) head++;
		printf("%d ", a[q[head]]);
	}
}

int main() {
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	getmin();
	printf("
");
	getmax();
	printf("
");
	return 0;
}

树剖

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

int n, m, root, mod, w[A], pre[A];

struct node {
	int to, nxt;
} e[A];

int head[A], cnt;

inline void add_edge(int from, int to) {	
	e[++cnt].to = to;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

namespace Seg {
	struct tree {
		int l, r, w, lazy;
	} t[A]; 
	#define lson rt << 1
	#define rson rt << 1 | 1
	inline void pushup(int rt) {
		t[rt].w = (t[lson].w + t[rson].w) % mod;
	}
	inline void pushdown(int rt) {
		t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy; 
		t[lson].lazy %= mod, t[rson].lazy %= mod;
		t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy; t[lson].w %= mod;
		t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy; t[lson].w %= mod;
		t[rt].lazy = 0;
	}
	void build(int rt, int l, int r) {
		t[rt].l = l, t[rt].r = r;
		if(l == r) { t[rt].w = w[pre[l]] % mod; return; }
		int mid = (l + r) >> 1;
		build(lson, l, mid); build(rson, mid + 1, r);
		pushup(rt); return;
	}
	void add(int rt, int l, int r, int val) {
		if(l <= t[rt].l && t[rt].r <= r) {
			t[rt].lazy = (t[rt].lazy + val) % mod;
			t[rt].w = (t[rt].w + (t[rt].r - t[rt].l + 1) * val) % mod;
			return;
		}
		if(t[rt].lazy) pushdown(rt);
		int mid = (t[rt].l + t[rt].r) >> 1;
		if(l <= mid) add(lson, l, r, val); 
		if(r > mid) add(rson, l, r, val);
		pushup(rt);
	}
	int asksum(int rt, int l, int r) {
		if(l <= t[rt].l && t[rt].r <= r) {
			return t[rt].w % mod;
		}
		if(t[rt].lazy) pushdown(rt);
		int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
		if(l <= mid) ans += asksum(lson, l, r);
		if(r > mid) ans += asksum(rson, l, r);
		return ans;
	}
}

int dfn[A], son[A], siz[A], dep[A], fa[A], top[A], tot;

void dfs1(int now, int fr) {
	siz[now] = 1, fa[now] = fr, dep[now] = dep[fr] + 1;
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(to == fr) continue; 
		dfs1(to, now);
		siz[now] += siz[to];
		if(siz[to] > siz[son[now]]) son[now] = to;
	}
}

void dfs2(int now, int tp) {
	dfn[now] = ++tot, pre[tot] = now, top[now] = tp; 
	if(son[now]) dfs2(son[now], tp);
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(to == fa[now] || to == son[now]) continue;
		dfs2(to, to);
	}
}

inline void add_qwq(int x, int y, int val) {
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		Seg::add(1, dfn[top[x]], dfn[x], val);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	Seg::add(1, dfn[x], dfn[y], val);
	return;
}

inline int asksum_qwq(int x, int y) {
	int ans = 0;
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		ans += Seg::asksum(1, dfn[top[x]], dfn[x]);
		ans %= mod;
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	ans += Seg::asksum(1, dfn[x], dfn[y]);
	ans %= mod;
	return ans % mod;
}

int main() {
	n = read(), m = read(), root = read(), mod = read();
	for(int i = 1; i <= n; i++) w[i] = read() % mod;
	for(int i = 1; i < n; i++) {
		int x = read(), y = read();
		add_edge(x, y), add_edge(y, x);
	}
	dfs1(root, 0);
	dfs2(root, root);
	Seg::build(1, 1, n);
	while(m--) { 
		int opt = read(), x, y, z;
		if(opt == 1) x = read(), y = read(), z = read() % mod, add_qwq(x, y, z);
		if(opt == 2) x = read(), y = read(), cout << asksum_qwq(x, y) % mod << '
';
		if(opt == 3) x = read(), z = read(), Seg::add(1, dfn[x], dfn[x] + siz[x] - 1, z);
		if(opt == 4) x = read(), cout << Seg::asksum(1, dfn[x], dfn[x] + siz[x] - 1) % mod << '
';
	}
	return 0;
}

求LCA

树剖求LCA

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], son[A], dfn[A], siz[A], fa[A], top[A], tot;

inline void add(int from, int to) {
	e[++cnt].to = to;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

void prepare(int now, int fr) {
	fa[now] = fr, dep[now] = dep[fr] + 1, siz[now] = 1;
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(to == fr) continue;
		prepare(to, now); siz[now] += siz[to];
		if(siz[to] > siz[son[now]]) son[now] = to;
	}
}

void dfs(int now, int tp) {
	top[now] = tp, dfn[now] = ++tot;
	if(son[now]) dfs(son[now], tp);
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(to == fa[now] || to == son[now]) continue;
		dfs(to, to);
	}
}

inline int LCA(int x, int y) {
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	return x;
}

int main() {
	n = read(), m = read(), R = read();
	for(int i = 1, x, y; i < n; i++) {
		x = read(), y = read();
		add(x, y), add(y, x);
	} 
	prepare(R, 0); dfs(R, R);
	while(m--) {
		int x = read(), y = read();
		cout << LCA(x, y) << '
';
	}
	return 0;
}

倍增求LCA

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], fa[A][23], lg[A];

inline void add(int from, int to) {
	e[++cnt].to = to;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

void dfs(int now, int fr) {
	fa[now][0] = fr, dep[now] = dep[fr] + 1;
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(to == fr) continue;
		dfs(to, now);
	}
}

inline int LCA(int x, int y) {
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 20; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}

int main() {
	n = read(), m = read(), R = read(); lg[1] = 0;
	for(int i = 2, x, y; i <= n; i++) {
		x = read(), y = read();
		add(x, y), add(y, x);
		lg[i] = lg[i >> 1] + 1;
	}
	
	dfs(R, 0); 
	
	for(int j = 1; (1 << j) <= n; j++) 
		for(int i = 1; i <= n; i++)
			fa[i][j] = fa[fa[i][j - 1]][j - 1];
	
	while(m--) {
		int x = read(), y = read();
		cout << LCA(x, y) << '
';
	}
	
	return 0;
}

ST表

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, a[B], f[B][25], lg[B];

inline int query(int l, int r) {
	int k = lg[r - l + 1];
	return max(f[l][k], f[r - (1 << k) + 1][k]);
}

int main() {
	n = read(), m = read(); lg[0] = -1;
	for(int i = 1; i <= n; i++) a[i] = read(), f[i][0] = a[i], lg[i] = lg[i >> 1] + 1;
	for(int j = 1; (1 << j) <= n; j++) 
		for(int i = 1; i <= n; i++)
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
	while(m--) {
		int x = read(), y = read();
		cout << query(x, y) << '
';
	}
	return 0;
}

数学/数论

求逆元

递推1~n的逆元

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;

const int A = 1e5 + 11;
const int B = 3e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, p;
ll inv[B];

int main() {
	n = read(), p = read();
	inv[1] = 1;
	for(int i = 2; i <= n; i++) {
		inv[i] = 1LL * (p - p / i) * inv[p % i] % p;
	}
	for(int i = 1; i <= n; i++) cout << inv[i] << '
';
	return 0;
}

矩阵快速幂

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e2 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x =  + (c ^ 48);
	return x * f;
}

int n, k;
struct matrix {
	int a[A][A];
	matrix() { memset(a, 0, sizeof(a)); }
	void init() { for(int i = 1; i <= n; i++) a[i][i] = 1; }
} ans, a;

matrix operator * (const matrix &x, const matrix &y) {
	matrix qwq;
	for(int k = 1; k <= n; k++) 
		for(int i = 1; i <= n; i++) 
			for(int j = 1; j <= n; j++)
				qwq.a[i][j] = (qwq.a[i][j] + x.a[i][k] * y.a[k][j] % mod) % mod;
	return qwq; 
}

inline void power() {
	while(k) {
		if(k & 1) ans = ans * a;
		a = a * a; k >>= 1;
	}
}

signed main() {
	n = read(), k = read();
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++) 
			a.a[i][j] = read();
	ans.init();
	power();
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			cout << ans.a[i][j] << " ";
		}
		puts("");
	}
	return 0;
}

快速乘

//知识点:快速乘
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

int a, b, p, ans;

int mul(int a, int b, int mod) {
	int res = 0;
	while(b) {
		if(b & 1) res = (res + a) % mod;
		a = (a + a) % mod;
		b >>= 1;
	}
	return res % mod;
}

signed main() {
	a = read(), b = read(), p = read();
	ans = mul(a, b, p);
	cout << ans << '
';
	return 0;
}

快速幂

//知识点:快速幂 
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

int a, b, p, ans;

int power(int a, int b, int mod) {
	int res = 1;
	while(b) {
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res % mod;
}

signed main() {
	a = read(), b = read(), p = read();
	ans = power(a, b, p);
	cout << ans << '
';
	return 0;
}

埃氏筛

void prime(int n) {
	cnt = 0;
	vis[0] = vis[1] = 1;
	for(int i = 2; i <= n; ++i) {
		if(!vis[i]) {
			p[++cnt] = i;
			for(int j = i * i; j <= n; j+=i) {
				vis[j] = true;
			}
		}
	}
}

线性筛

int vis[N], p[N], cnt;

void prepare() {
	vis[0] = vis[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) p[++cnt] = i;
		for(int j = 1; j <= cnt; j++) {
			if(i * p[j] > n) break;
			vis[i * p[j]] = 1;
			if(i % p[j] == 0) break;
		}
	}
}

动态规划

最长上升子序列

普通二分

//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 10001;

int f[N], a[N], n;
int len = 1;

int main() {
	memset(f, 0x3f, sizeof(f));
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	f[len] = a[1];
	for(int i = 2; i <= n; i++) {
		int l = 1, r = len, mid, rec;
		if(a[i] > f[len]) f[++len] = a[i];
		else {
			while(l <= r) {
				mid = (l + r) / 2;
				if(f[mid] >= a[i]) rec = mid, r = mid - 1;
				else l = mid + 1;
			}
			f[rec] = min(f[rec], a[i]);
		}
	}
	for(int i = 1; i <= len; i++) cout << f[i] << " ";
	cout << '
' << len << '
'; 
	return 0;
}
/*
9
7 2 1 5 6 4 3 8 9
*/

lower_bound

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 10001;

int f[N], a[N], n;
int len = 1;

int main() {
	memset(f, 0x3f, sizeof(f));
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	f[1] = a[1];
	for(int i = 2; i <= n; i++) {
		if(a[i] > f[len]) f[++len] = a[i];
		else { 
			int p = lower_bound(f + 1, f + len + 1 , a[i]) - f;
			f[p] = a[i];
		}
	}
	for(int i = 1; i <= len; i++) cout << f[i] << " ";
	cout << '
' << len << '
';
	return 0;
}

最长公共子序列

(n^2)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 1011;

int dp[N][N], a1[N], a2[N], n, m;

int main() {
	n = read();
	for(int i = 1; i <= n; i++) a1[i] = read();
	for(int i = 1; i <= n; i++) a2[i] = read();
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++) {
			dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
			if(a1[i] == a2[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
		}
	cout << dp[n][n] << '
';
	return 0;
}

图论

tarjan

#include <bits/stdc++.h>
using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    return x * f;
}

const int N = 1011;

struct node {
    int to, nxt;
} e[N];

int low[N], dfn[N], tot, topp = 0, sta[N], cnt, head[N];
bool vis[N];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].nxt = head[from];
    head[from] = tot;
}

void tarjan(int u) {
    dfn[u] = low[u] = ++cnt, sta[++topp] = u, vis[u] = 1;
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]) {
        do {
            cout << sta[topp] << ' ';
            vis[sta[topp--]] = 0;
        }while(u != sta[topp + 1]);
        cout << '
';
    }
}

int n, m;

int main() {
    n = read(), m = read();
    for(int i = 1; i <= m; i++) {
        int u = read(), v = read();
        add(u, v);
    }
    for(int i = 1; i <= n; i++) 
        if(!dfn[i]) tarjan(i);
}
/*
5 8
1 2
2 3
3 6
5 6
1 4
4 5
5 1
2 5
*/

最小生成树

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 2e5 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

int n, m, fa[A], cnt, ans;
struct node { int x, y, val; } e[A];
int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
bool cmp(node x, node y) { return x.val < y.val; }

int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i++) fa[i] = i;
	for(int i = 1; i <= m; i++) e[i].x = read(), e[i].y = read(), e[i].val = read();
	sort(e + 1, e + 1 + m, cmp);
	for(int i = 1; i <= m; i++) {
		int dx = find(e[i].x), dy = find(e[i].y);
		if(dx != dy) {
			fa[dy] = dx;
			ans += e[i].val;
			cnt++;
			if(cnt == n - 1) break;
		}
	}
	cout << ans << '
';
	return 0;
}

求树的直径

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

const int M = 3e5 + 11;

int n, cnt, k, ans, head[M], dep[M], vis[M];

struct node {
    int nxt, to;
} edge[M];

void add(int from, int to) {
    edge[++cnt].nxt = head[from];
    edge[cnt].to = to;
    head[from] = cnt;
}

void dfs(int x, int fx) {
    vis[x] = 1;
    for(int i = head[x]; i; i = edge[i].nxt) {
        int to = edge[i].to;
        if(to == fx) continue;
        dep[to] = dep[x] + 1;
        if(ans < dep[to]) {
            ans = dep[to];
            k = to;
        }
        dfs(to, x);
    }
}

int main() {
    n = read();
    for(int i = 1; i < n; i++) {
        int x = read(), y = read();
        add(x, y), add(y, x);
        ans = 0, dep[x] = 0, memset(vis, 0, sizeof(vis)); dfs(x, 0);
        ans = 0, dep[k] = 0, memset(vis, 0, sizeof(vis)); dfs(k, 0);
        cout << ans << '
';
    }
    return 0;
}

二分图匹配

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, E, ans;
struct node { int to, nxt; } e[A];
int head[A], cnt, match[A], vis[A];

inline void add(int from, int to) {
	e[++cnt].to = to;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

bool dfs(int now) {
	for(int i = head[now]; i; i = e[i].nxt) {
		int to = e[i].to;
		if(vis[to]) continue;
		vis[to] = 1;
		if(!match[to] || dfs(match[to])) {
			match[to] = now;
			return 1;
		}
	}
	return 0;
} 

int main() {
	n = read(), m = read(), E = read();
	for(int i = 1, x, y; i <= E; i++) {
		x = read(), y = read();
		if(x > n || y > m) continue;
		add(x, y);
	}
	for(int i = 1; i <= n; i++) {
		memset(vis, 0, sizeof(vis));
		if(dfs(i)) ans++;
	}
	cout << ans << '
';
	return 0;
}

最短路

堆优化dij

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, dis[A], S;
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
	e[++cnt].to = to;
	e[cnt].val = val;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

struct edge {
	int x, y;
	bool operator < (const edge &qwq) const {
		return y > qwq.y;
	}
};

priority_queue<edge> Q;
inline void ZDL() {
	memset(dis, inf, sizeof(dis));
	dis[S] = 0;
	Q.push((edge) {S, 0});
	while(!Q.empty()) {
		int u = Q.top().x, d = Q.top().y; Q.pop();
		if(d != dis[u]) continue;
		for(int i = head[u]; i; i = e[i].nxt) {
			int to = e[i].to;
			if(dis[to] > dis[u] + e[i].val) {
				dis[to] = dis[u] + e[i].val;
				Q.push((edge) {to, dis[to]});
			}
		}
	}
}

int main() {
//	freopen("testdata.in", "r", stdin);
	n = read(), m = read(), S = read();	
	for(int i = 1, x, y, val; i <= m; i++) {
		x = read(), y = read(), val = read();
		add(x, y, val);
	}
	ZDL();
	for(int i = 1; i <= n; i++) {
		if(dis[i] == inf) cout << "2147483647 ";
		else cout << dis[i] << " ";
	}
	return 0;
}

SPFA

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, dis[A], S, vis[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
	e[++cnt].to = to;
	e[cnt].val = val;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

queue <int> Q;
inline void SPFA() {
	memset(dis, inf, sizeof(dis));
	dis[S] = 0, vis[S] = 1;
	Q.push(S);
	while(!Q.empty()) {
		int u = Q.front(); Q.pop(); vis[u] = 0;
		for(int i = head[u]; i; i = e[i].nxt) {
			int to = e[i].to;
			if(dis[to] > dis[u] + e[i].val) {
				dis[to] = dis[u] + e[i].val;
				if(!vis[to]) {
					vis[to] = 1;
					Q.push(to);
				}
			}
		}
	}
}

signed main() {
	n = read(), m = read(), S = read();	
	for(int i = 1, x, y, val; i <= m; i++) {
		x = read(), y = read(), val = read();
		add(x, y, val);
	}
	SPFA();
	for(int i = 1; i <= n; i++) cout << dis[i] << " ";
	return 0;
}

判负环

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, dis[A], S = 1, vis[A], tot[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
	e[++cnt].to = to;
	e[cnt].val = val;
	e[cnt].nxt = head[from];
	head[from] = cnt;
}

inline bool SPFA() {
	memset(dis, inf, sizeof(dis));
	dis[S] = 0, vis[S] = 1, tot[S] = 1;
	queue <int> Q;
	Q.push(S);
	while(!Q.empty()) {
		int u = Q.front(); Q.pop(); vis[u] = 0;
		for(int i = head[u]; i; i = e[i].nxt) {
			int to = e[i].to;
			if(dis[to] > dis[u] + e[i].val) {
				if(++tot[to] >= n) return 1;
				dis[to] = dis[u] + e[i].val;
				if(!vis[to]) {
					vis[to] = 1;
					Q.push(to);
				}
			}
		}
	}
	return 0;
}

signed main() {
	int T = read();
	while(T--) {
		memset(head, 0, sizeof(head));	
		memset(vis, 0, sizeof(vis));
		memset(tot, 0, sizeof(tot));
		n = read(), m = read();
		for(int i = 1, x, y, val; i <= m; i++) {
			x = read(), y = read(), val = read();
			add(x, y, val);
			if(val >= 0) add(y, x, val);
		}
		if(SPFA()) puts("YE5");
		else puts("N0");
	}
	return 0;
}

字符串

(hash)

/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define ull unsigned long long
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 211;

char pa[N][N], meng[N];
int n, m, a[N], l[N], ans, cnt[N];
ull p[N], cnm[N][N], sjp[N];


bool query(int l1, int r1,int now) {
	ull h1, h2;
	h1 = sjp[r1] - sjp[l1 - 1] * p[r1 - l1 + 1];
	h2 = cnm[now][l[now]];
	return h1 == h2;
}

void work2() {//cnm
	memset(sjp, 0, sizeof(sjp));
	int len = strlen(meng + 1);
	for(int i = 1; i <= len; i++) {
		sjp[i] = sjp[i - 1] * 27 + meng[i] - 'a' + 1;
	}
	for(int i = 1; i <= m; i++) {
		for(int j = 1; j <= len; j++) {
			if(meng[j] == pa[i][1]) {
				if(query(j, j + l[i] - 1, i)) ans += j * a[i];
			}
		}
	}
}

int main() {
	freopen("dream.in", "r", stdin);
	freopen("dream.out", "w", stdout);
	n = read(), m = read();
	p[0] = 1;
	for(int i = 1; i <= 200; i++) p[i] = p[i - 1] * 27ull;
	for(int i = 1; i <= m; i++) scanf("%s", pa[i] + 1), l[i] = strlen(pa[i] + 1);
	for(int i = 1; i <= m; i++)
		for(int j = 1; j <= l[i]; j++)
			cnm[i][j] = cnm[i][j - 1] * 27 + pa[i][j] - 'a' + 1;
	for(int i = 1; i <= m; i++) a[i] = read();
	for(int i = 1; i <= n; i++) scanf("%s", meng + 1), work2();
	cout << ans << '
';
	return 0;
}

KMP

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, nxt[A];
char s[A], t[A];

void get_nxt() {
	int p = 0;
	for(int i = 2; i <= m; i++) {
		while(p && t[i] != t[p + 1]) p = nxt[p];
		if(t[i] == t[p + 1]) ++p;
		nxt[i] = p;
	}
}

int main() {
	scanf("%s", s + 1); scanf("%s", t + 1);
	n = strlen(s + 1), m = strlen(t + 1);
	get_nxt();
	int p = 0;
	for(int i = 1; i <= n; i++) {
		while(p && s[i] != t[p + 1]) p = nxt[p];
		if(s[i] == t[p + 1]) {
			++p;
			if(p == m) {
				cout << i - m + 1 << '
';
				p = nxt[p];
			}
		}
	}
	for(int i = 1; i <= m; i++) cout << nxt[i] << " ";
	return 0;
}
原文地址:https://www.cnblogs.com/loceaner/p/11631856.html