• CSP-S考前整理合集


    复赛前整理整理……涨涨RP

    本文主要收集整理各类板子的代码。


    一·IO优化

    快速读入

    template<class T>
    inline T read(T &x) {
    	x = 0; int w = 1, ch = getchar();
    	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
    	return x *= w;
    }
    

    输出

    输出不再写单独函数
    
    答案输出用printf,调试信息一律std::cout<<……
    

    二·数论

    欧几里得算法

    用处:求最大公约数

    int gcd(int a, int b) {return !b ? a : gcd(b, a % b);}
    
    int main() {
    	int a, b;
    	read(a), read(b);
    	int G = gcd(a, b);
    }
    

    时间复杂度:(O(logn))

    扩展欧几里得算法

    用处:求解逆元,解线性同余方程……

    void exgcd(int a, int b, int &d, int &x, int &y) {
    	if (!b) {d = a; x = 1; y = 0; return ;}
    	else exgcd(b, a % b, d, y, x), y -= a / b * x;
    }
    
    int main() {
    	int a, b, x, y;
    	exgcd(a, p, x, y);
    	int G = (x % p + p) % p; // a 在 %p意义下的逆元
    }
    

    时间复杂度:(O(logn))

    快速幂

    用处:求解逆元……

    #define LL long long
    const int MOD = 1e9 + 7;
    
    LL quick_pow(LL a, LL b, LL mod) {
    	LL ans = 1;
    	while (b) {
    		if (b & 1) ans = ans * a % mod;
    		b >>= 1;
    		a = a * a % mod;
    	}
    	return ans % mod;
    }
    
    int main() {
    	LL a, b;
    	LL G = quick_pow(a, b, MOD); // a ^ b % MOD 
    }
    

    时间复杂度:(O(logn))

    龟速乘

    用处:乘法爆(long long)时使用

    #define LL long long
    const int MOD = 1e9 + 7;
    
    LL quick_mul(LL a, LL b, LL mod) {
    	LL ans = 1;
    	while (b) {
    		if (b & 1) ans = (ans + a) % mod;
    		b >>= 1;
    		a = (a + a) % mod;
    	}
    	return ans % mod;
    }
    
    int main() {
    	LL a, b;
    	LL G = quick_mul(a, b, MOD); // a * b % MOD 
    }
    

    时间复杂度:(O(logn))

    逆元

    用处:计算(frac{a}{b}mod P)

    #define LL long long
    const int maxn = 3e5 + 5;
    const int MOD = 1e9 + 7;
    int inv[maxn];
    
    LL quick_pow(LL a, LL b, LL mod) {
    	LL ans = 1;
    	while (b) {
    		if (b & 1) ans = ans * a % mod;
    		b >>= 1;
    		a = a * a % mod;
    	}
    	return ans % mod;
    }
    
    void exgcd(int a, int b, int &d, int &x, int &y) {
    	if (!b) {d = a; x = 1; y = 0; return ;}
    	else exgcd(b, a % b, d, y, x), y -= a / b * x;
    }
    
    
    int main() {
    	LL a;
    	LL G = quick_pow(a, MOD - 2, MOD); // a 在模MOD意义下逆元, a必须与MOD互质
    
    	LL x, y;
    	exgcd(a, MOD, x, y);
    	LL G = (x % MOD + MOD) % MOD // a 在模MOD意义下逆元,无特殊要求
    
    	LL n;
    	inv[1] = 1;
    	for (int i = 2; i <= n; i++) inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD; 
    	// 线性求逆元 
    }
    

    时间复杂度:前两种均为(O(logn)),最后一种为(O(n))

    质因数分解

    用处:求一个数的质因数,欧拉函数值……

    const int maxn = 3e5 + 5;
    int p[maxn], c[maxn], cnt;
    void divede(int n) {
    	for (int i = 2; i * i <= n; i++) 
    		if (n % i == 0) {
    			p[++cnt] = i;
    			while (n % i == 0) c[i]++, n /= i;
    		}
    	if (n > 1) p[++cnt] = n, c[n] = 1;
    }
    
    int main() {
    	int n;
    	divide(n);
    }
    

    时间复杂度:(O(sqrt n))

    线性筛法求素数及积性函数

    线性筛素数

    const int maxn = 3e5 + 5;
    int prime[maxn], is_prime[maxn], cnt;
    
    void euler_phi(int n) {
    	is_prime[1] = 1;
    	for (int i = 2; i <= n; i++) {
    		if (!is_prime[i]) prime[++cnt] = i;
    		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
    			is_prime[i * prime[j]] = 1;
    			if (i % prime[j] == 0) break;
    		}
    	}
    }
    
    int main() {
    	euler_phi(maxn);
    }
    

    线性筛欧拉函数

    const int maxn = 3e5 + 5;
    int prime[maxn], phi[maxn], cnt;
    
    void phi_table(int n) {
    	phi[1] = phi[0] = 0;
    	for (int i = 2; i <= n; i++) {
    		if (!phi[i]) 
    			prime[++cnt] = i, phi[i] = i - 1;
    		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
    			if (i % prime[j] == 0) {
    				phi[i * prime[j]] = phi[i] * prime[j];
    				break;
    			}
    			phi[i * prime[j]] = phi[i] * (prime[j] - 1);
    		}
    	}
    }
    
    int main() {
    	phi_table(maxn);
    }
    

    线性筛约数个数

    const int maxn = 3e5 + 5;
    int prime[maxn], is_prime[maxn], d[maxn], st[maxn], cnt;
    
    void phi_table(int n) {
    	is_prime[1] = 1, d[1] = 1;
    	for (int i = 2; i <= n; i++) {
    		if (!is_prime[i]) 
    			prime[++cnt] = i, d[i] = 2, st[i] = 1;
    		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
    			is_prime[i * prime[j]] = 1;
    			if (i % prime[j] == 0) {
    				d[i * prime[j]] = d[i] / (st[i] + 1) * (st[i] + 2);
    				st[i * prime[j]] = st[i] + 1; break;
    			}
    			d[i * prime[j]] = d[i] * d[prime[j]], st[i * prime[j]] = 1;
    		}
    	}
    }
    
    int main() {
    	phi_table(maxn);
    }
    

    线性筛约数和

    const int maxn = 3e5 + 5;
    int prime[maxn], is_prime[maxn], sd[maxn], st[maxn], cnt;
    
    void phi_table(int n) {
    	is_prime[1] = 1, sd[1] = 1;
    	for (int i = 2; i <= n; i++) {
    		if (!is_prime[i]) 
    			prime[++cnt] = i, sd[i] = i + 1, st[i] = i + 1;
    		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
    			is_prime[i * prime[j]] = 1;
    			if (i % prime[j] == 0) {
    				sd[i * prime[j]] = sd[i] / st[i] + 1 * (st[i] * prime[j] + 1);
    				st[i * prime[j]] = st[i] * prime[j] + 1; break;
    			}
    			sd[i * prime[j]] = sd[i] * sd[prime[j]], st[i * prime[j]] = prime[j] + 1;
    		}
    	}
    }
    
    int main() {
    	phi_table(maxn);
    }
    

    时间复杂度:以上代码复杂度均为(O(n))

    中国剩余定理

    用处:求解模数互质的同余方程组

    #define LL long long
    const int maxn = 3e5 + 5;
    LL a[maxn], m[maxn];
    
    
    void exgcd(int a, int b, int &x, int &y) {
    	if (!b) {x = 1, y = 0; return ;}
    	else exgcd(b, a % b, y, x), y -= a / b * x;
    }
    
    LL China(int n, LL *a, LL*m) {
    	LL G = 1, ans = 0, x, y;
    	for (int i = 0; i < n; i++) G *= m[i];
    	for (int i = 0; i < n; i++) {
    		LL w = G / m[i];
    		exgcd(w, m[i], x, y);
    		x = (x % m[i] + m[i]) % m[i];
    		ans = (ans + x * w * a[i]) % G;
    	}
    	return (ans + G) % G;
    }
    
    int main() {
    	int n;
    	scanf("%d", &n);
    	for (int i = 0; i < n; i++) scanf("%lld%lld", &a[i], &m[i]);
    	printf("%lld
    ", China(n, a, m));
    }
    
    

    时间复杂度:(O(nlogn))

    整除分块

    用处:求解类似于(sum_{i=1}^{n}f(i)lfloorfrac{n}{i} floor)的式子,其中(f(i))应该可以用前缀和预处理

    #define LL long long
    
    int main() {
    	for (LL l = 1, r; l <= n; l = r + 1) {
    		r = n / (n / l);
    		ans = (r - l + 1) * (n / l);
    	}
    	printf("%lld
    ", ans);
    }
    
    

    时间复杂度:(O(sqrt n))

    组合数

    int quick_pow(int a, int b, int mod) {
    	int ans = 1;
    	while (b) {
    		if (b & 1) ans = ans * a % mod;
    		b >>= 1;
    		a = a * a % mod;
    	}
    	return ans % mod;
    }
    
    void init() {
    	fac[0] = 1;
    	for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % MOD;
    	for (int i = 1; i <= n; i++) ifac[i] = quick_pow(fac[i], MOD - 2, MOD);
    }
    
    int C(int n, int m) {
    	return fac[n] % MOD * ifac[m] % MOD * ifac[n - m] % MOD;
    }
    

    三·图论

    图的存储与遍历

    链式前向星

    const int maxn = 3e5 + 5;
    int n, m, tot, head[maxn];
    
    struct Edge {
    	int to, val, nxt;
    	Edge(int _to, int _val, int _nxt) {
    		this -> to = _to;
    		this -> val = _val;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to, int val) {edge[++tot] = Edge(to, val, head[from]), head[from] = tot;}
    
    void dfs(int u, int f) {
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (v == f) continue;
    		dfs(v, u);
    	}
    }
    

    时间复杂度:(O(n))

    vector

    using std::pair;
    using std::make_pair;
    using std::vector;
    #define pii pair<int, int>
    const int maxn = 3e5 + 5;
    
    vector<pii >G[maxn];
    
    void add(int from, int to, int val) {
    	G[from].push_back(make_pair(to, val));
    	G[to].push_back(make_pair(from, val));
    }
    
    void dfs(int u, int f) {
    	for (int i = 0; i < G[u].size(); i++) {
    		int v = G[u][i];
    		if (v == f) continue;
    		dfs(v, u);
    	}
    }
    

    时间复杂度:(O(n)),常数略大……

    最短路算法

    Floyd多源最短路

    int g[1007][1007];
    
    void init() {
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    			if (i == j) g[i][j] = 0;
    			else g[i][j] = 0x3f3f3f3f;
    	for (int i = 1; i <= m; i++) {
    		int x, y, z;
    		read(x), read(y), read(z);
    		g[x][y] = g[y][x] = min(g[x][y], z);		
    	}
    }
    
    void Floyd() {
    	for (int k = 1; k <= n; k++) 
    		for (int i = 1; i <= n; i++)
    			for (int j = 1; j <= n; j++)
    				g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
    }
    
    

    时间复杂度:(O(n^3))

    Dijkstra单源最短路

    using std::priority_queue;
    const int maxn = 3e5 + 5;
    int n, m, tot, head[maxn], dis[maxn], vis[maxn];
    
    struct Edge {
    	int to, val, nxt;
    	Edge(int _to, int _val, int _nxt) {
    		this -> to = _to;
    		this -> val = _val;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to, int val) {edge[++tot] = Edge(to, val, head[from]), head[from] = tot;}
    
    struct Node {
    	int w, now;
    	bool operator < (const Node &rhs) const {
    		return w > rhs.w;
    	}
    };
    
    void djikstra(int S) {
    	memset(dis, 0x3f, sizeof(dis));
    	memset(vis, 0, sizeof(0));
    	priority_queue<Node>pq;
    	pq.push((Node){0, S}), dis[S] = 0;
    	while (!pq.empty()) {
    		Node x = pq.top(); pq.pop();
    		int u = x.now();
    		if (vis[u]) continue;
    		vis[u] = 1;
    		for (int i = head[u]; i; i = edge[i].nxt) {
    			int v = edge[i].to;
    			if (dis[v] > dis[u] + edge[i].val) {
    				dis[v] = dis[u] + edge[i].val;
    				pq.push((Node){dis[v], v});
    			}
    		}
    	}
    }
    

    Spfa单源最短路

    using std::queue;
    const int maxn = 3e5 + 5;
    int n, m, tot, head[maxn], dis[maxn], vis[maxn];
    
    struct Edge {
    	int to, val, nxt;
    	Edge(int _to, int _val, int _nxt) {
    		this -> to = _to;
    		this -> val = _val;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to, int val) {edge[++tot] = Edge(to, val, head[from]), head[from] = tot;}
    
    void spfa(int S) {
    	memset(dis, 0x3f, sizeof(dis));
    	memset(vis, 0, sizeof(vis));
    	queue<int>q; 
    	q.push(S), dis[S] = 0, vis[S] = 1;
    	while (!q.empty()) {
    		int u = q.front();
    		q.pop(); vis[u] = 0;
    		for (int i = head[u]; i; i = edge[i].nxt) {
    			int v = edge[i].to;
    			if (dis[v] > dis[u] + edge[i].val) {
    				dis[v] = dis[u] + edge[i].val;
    				if (!vis[v]) {
    					vis[v] = 1;
    					q.push(v);
    				}
    			}
    		}
    	} 
    }
    

    并查集

    严格讲貌似不属于图论,不过就在这里放着吧……

    int fa[maxn];
    
    struct DSU {
    	int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    	bool judge(int x, int y) {return find(x) == find(y);}
    	void merge(int x. int y) {fa[find(x)] = find(y);}
    }T;
    
    void init() {
    	for (int i = 1; i <= n; i++) fa[i] = i;
    	......
    }
    

    时间复杂度:(O(nlogn))

    Kruskal最小生成树算法

    用处:求最小生成树

    struct Edge {
    	int from, to, val;
    	bool operator < (const Edge &rhs) const {
    		return val < rhs.val;
    	}
    }edge[maxn];
    
    int fa[maxn];
    
    struct DSU {
    	int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    	bool judge(int x, int y) {return find(x) == find(y);}
    	void merge(int x. int y) {fa[find(x)] = find(y);}
    }T;
    
    int main() {
    	read(n), read(m);
    	for (int i = 1; i <= m; i++) read(edge[i].from), read(edge[i].to), read(edge[i].val);
    		std::sort(edge + 1, edge + m + 1);
    	for (int i = 1; i <= n; i++) fa[i] = i;
    	int sum = 0, cnt = 0;
    	for (int i = 1; i <= m; i++) {
    		int x = edge[i].from, y = edge[i].to;
    		if (T.judge(x, y)) continue;
    		T.merge(x, y);
    		sum += edge[i].val;
    		++cnt;
    		if (cnt == n - 1) break;
    	}
    	printf("%d
    ", sum);
    }
    

    最近公共祖先

    倍增LCA

    const int maxn = 3e5 + 5;
    int n, m, tot, head[maxn], dep[maxn], fa[maxn][22], lg[maxn];
    
    struct Edge {
    	int to, nxt;
    	Edge (int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    void dfs(int u, int f) {
    	dep[u] = dep[f] + 1;
    	fa[u][0] = f;
    	for (int i = 1; (1 << i) <= dep[u]; i++)
    		fa[u][i] = fa[fa[u][i - 1]][i - 1];
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (v == f) continue;
    		dfs(v, u);
    	}
    }
    
    int query(int x, int y) {
    	if (dep[x] < dep[y]) std::swap(x, y);
    	while (dep[x] > dep[y])
    		x = fa[x][lg[dep[x] - dep[y]] - 1];
    	if (x == y) return x;
    	for (int j = lg[dep[x]] - 1; j >= 0; j--)
    		if (fa[x][j] != fa[y][j])
    			x = fa[x][j], y = fa[y][j];
    	return fa[x][0];
    }
    
    int main() {
    	for (int i = 1; i <= n; i++) lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
    	......
    }
    

    时间复杂度:(O(nlogn))

    树剖LCA

    const int maxn = 3e5 + 5;
    int n, m, tot, head[maxn], dep[maxn], siz[maxn], fa[maxn], son[maxn], top[maxn];
    
    struct Edge {
    	int to, nxt;
    	Edge (int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    void dfs1(int u, int f, int deep) {
    	dep[u] = deep, fa[u] = f, siz[u] = 1;
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (v == f) continue;
    		dfs1(v, u, deep + 1);
    		siz[u] += siz[v];
    		if (siz[v] > siz[son[u]]) son[u] = v;
    	}
    }
    
    void dfs2(int u, int topf) {
    	top[u] = topf;
    	if (!son[u]) return ;
    	dfs2(son[u], topf);
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (v == fa[u] || v == son[u]) continue;
    		dfs2(v, v);
    	}
    }
    
    int query(int x, int y) {
    	while (top[x] != top[y]) {
    		if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
    		x = fa[top[x]];
    	}
    	return dep[x] < dep[y] ? x : y;
    }
    
    int main() {
    	......
    	dfs1(1, 0, 1);
    	dfs2(1, 1);
    	......
    }
    

    Tarjan 算法

    割点/割顶

    const int maxn = 3e5 + 5;
    int n, m, tot, num, head[maxn], dfn[maxn], low[maxn], cnt[maxn];
    
    struct Edge {
    	int to, nxt;
    	Edge (int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    void tarjan(int u, int f) {
    	dfn[u] = low[u] = ++num;
    	int flag = 0;
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (!dfn[v]) {
    			tarjan(v, fa);
    			low[u] = min(low[u], low[v]);
    			if (low[v] >= dfn[u] && x != fa) cnt[u] = 1;
    			if (x == fa) flag++;
    		}
    		low[u] = min(low[u], dfn[v]);
    	}
    	if (x == fa && flag >= 2) cnt[u] = 1;
    }
    

    割边

    const int maxn = 3e5 + 5;
    int n, m, tot, num, head[maxn], dfn[maxn], low[maxn], bridge[maxn];
    
    struct Edge {
    	int to, nxt;
    	Edge (int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    void tarjan(int u, int in_edge) {
    	dfn[u] = low[u] = ++num;
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to;
    		if (!dfn[v]) {
    			tarjan(v, i);
    			low[u] = min(low[u], low[v]);
    			if (low[v] > dfn[u]) bridge[i] = bridge[i ^ 1] = 1;
    		}
    		else if (i != (in_edge ^ 1))
    			low[u] = min(low[u], dfn[v]);
    	}
    }
    
    int main() {
    	tot = 1;
    	......
    }
    

    强连通分量

    const int maxn = 3e5 + 5;
    int n, m, tot, num, num_node, head[maxn], dfn[maxn], low[maxn], st[maxn], belong[maxn], cnt, vis[maxn];
    
    struct Edge {
    	int to, nxt;
    	Edge (int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    void tarjan(int u, int in_edge) {
    	dfn[u] = low[u] = ++num;
    	st[++cnt] = u; vis[u] = 1;
    	for (int i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[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]) {
    		int y;
    		++num_node;
    		while (y = st[cnt--]) {
    			belong[y] = num_node;
    			vis[y] = false;
    			if (u == y) break; 
    		}
    	}
    }
    
    int main() {
    	......
    }
    

    时间复杂度:上述代码均为(O(n))

    二分图最大匹配

    匈牙利算法

    用处:据长者说,(CSP)可能要考……

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    bool vis[1005];
    int n, m, e, a[1005][1005], belong[1005];
    
    template<class T>
    inline T read(T &x) {
    	x = 0; int w = 1, ch = getchar();
    	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
    	return x *= w;
    } 
    
    bool judge(int x) {
    	for (int i = 1; i <= m; i++)
    		if (a[x][i] && !vis[i]) {
    			vis[i] = 1;
    			if (!belong[i] || judge(belong[i])) {
    				belong[i] = x;
    				return true;
    			}
    		}
    	return false;
    }
    
    int main() {
    	read(n), read(m), read(e);
    	for (int i = 1; i <= e; i++) {
    		int x, y;
    		read(x), read(y);
    		a[x][y] = 1;
    	}
    	int ans = 0;
    	for (int i = 1; i <= n; i++) {
    		memset(vis, false, sizeof(vis));
    		if (judge(i)) ++ans;
    	}
    	std::cout << ans << '
    ';
    	return 0;
    }
    

    时间复杂度:(O(n^2m))

    Dinic实现二分图匹配

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define min(a, b) ((a) < (b) ? (a) : (b))
     
    const int maxn = 1e6 +5;
    const int INF = 1e9;
    int n, m, e, head[maxn], tot = -1, s, t;
    int maxflow, dep[maxn];
    std::queue<int>q;
    
    template<class T>
    inline T read(T &x) {
        x = 0; int w = 1, ch = getchar();
        for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
        return x *= w;
    }
    
    struct Edge {
        int to, val, nxt;
        Edge(int y, int w, int next) {
            to = y, val = w, nxt = next;
        }
        Edge(){
        }
    }edge[maxn << 1];
    
    void add(int from, int to, int val)
    {
        edge[++tot] = Edge(to, val, head[from]); head[from] = tot;
    }
    
    bool bfs(int s, int t)
    {
        memset(dep, 0x7f, sizeof(dep));
        while (!q.empty()) q.pop();
        dep[s] = 0;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i != -1; i = edge[i].nxt) {
                int v = edge[i].to;
                if (dep[v] > INF && edge[i].val) {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                    if (v == t) return true;
                }
            }
        }
        return false;
    }
    
    int dfs(int u, int t, int limit)
    {
        if (!limit || u == t) return limit;
        int flow = 0, f;
        for (int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].to;
            if (dep[v] == dep[u] + 1 && edge[i].val) {
                f = dfs(v, t, min(limit, edge[i].val));
                if (!f) dep[v] = 0;
                flow += f;
                limit -= f;
                edge[i].val -= f;
                edge[i ^ 1].val += f;
                if (!limit) break;
            }
        }
        return flow;
    }
    
    void dinic(int s, int t)
    {
        while (bfs(s, t))
            maxflow += dfs(s, t, INF);
    }
    
    int main()
    {
        memset(head, -1, sizeof(head));
        int x, y;
        read(n), read(m), read(e);
        s = n + m + 2, t = n + m + 3;
        for (int i = 1; i <= e; i++) {
            read(x), read(y);
            if (x > n || y > m) continue;
            add(x, y + n, 1);
            add(y + n, x, 0);
        }
        for (int i = 1; i <= n; i++)
            add(s, i, 1), add(i, s, 0);
        for (int i = 1; i <= m; i++)
            add(i + n, t, 1), add(t, i + n, 0);
        dinic(s, t);
        printf("%d
    ", maxflow);
        return 0;
    }
    

    时间复杂度:(O(nsqrt m))

    四·动态规划

    最长上升子序列LIS

    const int INF = 1e9;
    int d[100005];
    
    void solve() {
        d[0] = -INF;
        for (int i = 1; i <= n; i++) d[i] = INF;
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            int pos = std::lower_boud(d, d + i, a[i]) - d;
            d[pos] = std::min(d[pos], a[i]);
            ans = std::max(ans, pos);
        }
    }
    

    时间复杂度:(O(nlogn))

    最长公共子序列LCS

    const int INF = 1e9;
    int a[1001], b[1001], f[1001][1001];
    
    void solve() {
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) {
                if (a[i] == b[j]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
                else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            }
        ans : f[n][n]
    }
    

    时间复杂度:(O(n^2))

    背包类问题

    01背包

    const int INF = 1e9;
    int w[1001], v[1001], f[10001];
    
    void solve() {
        for (int i = 1; i <= n; i++) 
            scanf("%d%d", &w[i], &v[i]);
        for (int i = 1; i <= n; i++)
            for (int j = V; j >= w[i]; j--)
                f[i] = std::max(f[i], f[j - w[i]] + v[i]);
    }
    

    时间复杂度:(O(nV))

    完全背包

    const int INF = 1e9;
    int w[1001], v[1001], f[10001];
    
    void solve() {
        for (int i = 1; i <= n; i++) 
            scanf("%d%d", &w[i], &v[i]);
        for (int i = 1; i <= n; i++)
            for (int j = w[i]; j <= V; j++)
                f[i] = std::max(f[i], f[j - w[i]] + v[i]);
    }
    

    二进制优化多重背包

    const int INF = 1e9;
    int w, v, k, f[10001];
    
    void solve() {
        while (n--) {
            scanf("%d%d%d", &w, &v, &k);
            for (int d = 1; d < k; k -= d; d <<= 1) 
                for (int i = V; i >= d * w; i--)
                    f[i] = std::max(f[i], f[i - w * d] + d * v);
            for (int i = V; i >= k * w; k--)
                f[i] = std::max(f[i], f[i - w * k] + k * v);
        }
    }
    

    时间复杂度:(O(nVlogK))

    二维费用背包

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    int f[1007][1007], a[1007], b[1007], c[1007], n, m, x;
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin >> n >> m >> x;
        for (int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> c[i];
        for (int i = 1; i <= n; i++)
            for (int j = m; j >= b[i]; j--)
                for (int v = x; v >= c[i]; v--)
                f[j][v] = std::max(f[j][v], f[j - b[i]][v - c[i]] + a[i]);
        cout << f[m][x] << '
    ';        
        return 0;
    }
    

    时间复杂度:(O(nmx))

    树形动规问题

    【JSOI2018】潜入行动

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define rint register int
    #define LL long long
     
    const int maxn = 1e5 + 5;
    const int MOD = 1e9 + 7;
    int n, k, tot, head[maxn], f[maxn][105][4], siz[maxn], g[105][4];
    
    /*
    0 -> 安装且被监听
    1 -> 安装且不被监听
    2 -> 不安装被监听
    3 -> 不安装不被监听
    */
    
    struct Edge {
    	int to, nxt;
    	Edge(int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    template<class T>
    inline T read(T &x) {
    	x = 0; int w = 1, ch = getchar();
    	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
    	return x *= w;
    } 
    
    void dfs(int u, int fa) {
    	f[u][1][1] = 1; f[u][0][3] = 1; siz[u] = 1;
    	for (rint i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to; 
    		if (v == fa) continue;
    		dfs(v, u);
    		siz[u] += siz[v]; memcpy(g, f[u], sizeof(g));
    		for (rint j = min(siz[u], k); ~j; j--) f[u][j][0] = f[u][j][1] = f[u][j][2] = f[u][j][3] = 0;
    		for (rint j = min(siz[u], k); ~j; j--) {
    			for (rint p = max(0, j + siz[v] - siz[u]); p <= min(siz[v], j); p++) {
    				f[u][j][3] += ((LL)f[v][p][2] * g[j - p][3]) % MOD, f[u][j][3] %= MOD;
    				f[u][j][2] += ((LL)(f[v][p][0] % MOD + f[v][p][2] % MOD) % MOD) *
    							  ((g[j - p][2] % MOD + g[j - p][3] % MOD) % MOD) % MOD; 
    				f[u][j][2] %= MOD;
    				f[u][j][1] += ((LL)(f[v][p][2] % MOD + f[v][p][3] % MOD)) % MOD * 
    							  g[j - p][1] % MOD; f[u][j][1] %= MOD;
    				f[u][j][0] += ((LL)(f[v][p][0] + f[v][p][1] % MOD) + (f[v][p][2] + f[v][p][3]) % MOD)
    				 			  % MOD * ((g[j - p][1] % MOD+ g[j - p][0] % MOD)) % MOD; f[u][j][0] %= MOD;
    			}
    			f[u][j][0] = (f[u][j][0] - f[u][j][1] + MOD) % MOD; 
    			f[u][j][2] = (f[u][j][2] - f[u][j][3] + MOD) % MOD; 	
    		}
    	}
    }
    
    int main() {
    	int x, y;
    	read(n), read(k);
    	for (int i = 1; i < n; i++) {
    		read(x), read(y);
    		add(x, y), add(y, x);
    	}
    	dfs(1, 0);
    	std::cout << f[1][k][0] + f[1][k][2]<< '
    ';
    	return 0;
    }
    

    时间复杂度:树形动规一般情况下为(O(n)),树形背包为严格(O(n^2))

    数位DP

    烦人的数学作业

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    
    const int maxn = 25;
    const int MOD = 1e9 + 7;
    int T, L, R;
    int val[maxn], f[maxn][maxn];
    
    template<class T>
    inline T read(T &x) {
        x = 0; int w = 1, ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48; ch = getchar();}
        return x *= w;
    }
    
    int dfs(int pos, int limit, int lead_zero, int k, int sum) {
        if (!pos) return sum;
        if (!limit && !lead_zero && f[pos][sum] != -1)
            return f[pos][sum];
        int lim = limit ? val[pos] : 9;
        int ans = 0;
        for (int i = 0; i <= lim; i++) {
            if (lead_zero && !i)
                ans += dfs(pos - 1, limit && (i == lim), 1, k, sum);
            else
                ans += dfs(pos - 1, limit && (i == lim), 0, k, sum + (i == k));
        }
        if (!limit && !lead_zero)
            f[pos][sum] = ans;
        return ans;
    }
    
    int solve(int n, int k) {
        memset(f, -1, sizeof(f));
        int len = 0;
        while (n) val[++len] = n % 10, n /= 10;
        return dfs(len, 1, 1, k, 0);
    }
    
    signed main() {
        read(T);
        while (T--) {
            int ans = 0;
            read(L), read(R);
            for (int i = 1; i <= 9; i++)
                ans += (((solve(R, i) - solve(L - 1, i) + MOD) % MOD) * i % MOD + MOD) % MOD, ans %= MOD;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    时间复杂度:(O()玄学不会证())

    状态压缩DP

    UVA11008 【Antimatter Ray Clearcutting】

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 70000; 
    int T, n, m, x[20], y[20], g[20][20]; //x,y储存坐标,g用于储存直线
    int f[maxn], N;
    // f用于记忆化,N为初始状态。
    void init()
    {
        memset(f, -1, sizeof(f));
        memset(g, 0, sizeof(g));  //多测不清空,爆零两行泪!!!
        scanf("%d%d", &n,   &m);
        N = (1 << n) - 1;  //搜索初始状态
        for (int i = 0; i < n; i++)
            scanf("%d%d", &x[i], &y[i]);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i == j) continue; 
                for (int k = n - 1; k >= 0; k--) {
                    g[i][j] <<= 1; //左移一位,为下一个点腾出位置
                    if ((x[j] - x[i]) * (y[k] - y[j]) == (y[j] - y[i]) * (x[k] - x[j]))
                        g[i][j]++; //表示这个点在这条直线上
                }
            }
        }
    }
    
    int Count(int k)
    {
        int cnt = 0;
        for (int i = 0; i < n; i++)
            if ((1 << i) & k) cnt++;
        return cnt;
    }
    
    int dfs(int now)
    {
        int cnt = Count(now); 
        // Count用于计算还有多少个点没删
        int& ans = f[now]; 
        // 这个取地址符一定要加!! 原因是后面f[now]也要改变
        if (cnt <= n - m) return ans = 0; 
        // 如果剩下的点小于n-m,那么就不用再删了,直接返回0
        else if (cnt == 1) return ans = 1;
        //如果还剩一个点,直接用一条直线来删
        else if (ans > -1) return ans;
        //记忆化,不解释
        ans = (1 << 30);
        //都没有,枚举直线更新状态
        for (int i = 0; i < n; i++) {
            if ((1 << i) & now) {
                // 保证i这个点还没有被删
                for (int j = i + 1; j < n; j++) {
                    if ((1 << j) & now) {
                        //保证j这个点没被删
                        int temp = now & (g[i][j] ^ N); //异或取补集,再取and,得到下一个状态
                        ans = min(ans, dfs(temp) + 1); //更新ans
                    }
                }
            }
        }
        return ans;
    }
    
    int main()
    {
        int t = 1;
        scanf("%d", &T);
        while (T--) {
            init(); //初始化
            printf("Case #%d:
    %d
    ", t++, dfs(N));
            if (T) puts("");
        }
        return 0;
    }
    

    时间复杂度:一般为指数级貌似是废话

    五·数据结构

    线段树

    用处:不说了,大家都知道……

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define max(a, b) ((a) > (b) ? (a) : (b))
    
    const int maxn = 1e5 + 5;
    int n, m, a[maxn], opt, l, r, v;
    
    struct Node {
    	int sum, tag;
    }z[maxn << 2];
    
    void build(int rt, int l, int r) {
    	if (l == r) {
    		z[rt].sum = a[l];
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(rt << 1, l, mid);
    	build(rt << 1 | 1, mid + 1, r);
    	z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
    }
    
    void modify(int rt, int l, int r, int x, int y, int v) {
    	z[rt].sum += (min(r, y) - max(l, x) + 1) * v;
    	if (x <= l && r <= y) {
    		z[rt].tag += v;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (x <= mid) modify(rt << 1, l, mid, x, y, v);
    	if (y > mid) modify(rt << 1 | 1, mid + 1, r, x, y, v);
    }
    
    int query(int rt, int l, int r, int x, int y, int tg) {
    	if (x <= l && r <= y) {
    		return z[rt].sum + (min(r, y) - max(l, x) + 1) * tg;
    	}
    	int mid = (l + r) >> 1;
    	int ret = 0;
    	if (x <= mid) ret += query(rt << 1, l, mid, x, y, tg + z[rt].tag);
    	if (y > mid) ret += query(rt << 1 | 1, mid + 1, r, x, y, tg + z[rt].tag); 
    	return ret;
    }
    
    signed main() {
    	scanf("%lld%lld", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    	build(1, 1, n);
    	for (int i = 1; i <= m; i++) {
    		scanf("%lld", &opt);
    		if (opt == 1) {
    			scanf("%lld%lld%lld", &l, &r, &v);
    			modify(1, 1, n, l, r, v);
    		}
    		else {
    			scanf("%lld%lld", &l, &r);
    			printf("%lld
    ", query(1, 1, n, l, r, 0));
    		}
    	}	
    	return 0;
    }
    

    时间复杂度:(O(nlogn))

    树状数组

    用处:大家都知道……

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    #define lowbit(x) ((x) & -(x))
    
    const int maxn = 5e5 + 5;
    int n, m;
    
    template<class T>
    inline T read(T &x) {
        x = 0; int w = 1, ch = getchar();
        for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
        return x *= w;
    }
    
    struct FenwickTree {
        int bit[maxn];
        void add(int x, int v) {for (; x <= n; x += lowbit(x)) bit[x] += v;}
        int query(int x) {int ret = 0; for (; x; x -= lowbit(x)) ret += bit[x]; return ret;}
    }T;
    
    signed main() {
        read(n), read(m);
        for (int i = 1; i <= n; i++) {
            int temp; read(temp);
            T.add(i, temp);
        }
        int opt, x, y;
        for (; m; m--) {
            read(opt), read(x), read(y);
            if (opt == 1) T.add(x, y);
            else printf("%lld
    ", T.query(y) - T.query(x - 1));
        }
        return 0;
    }
    

    时间复杂度:(O(nlogn))

    ST表

    用处:………………

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    
    const int maxn = 1e6 + 5;
    int n, m, f[maxn][22];
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &f[i][0]);
        for (int j = 1; (1 << j) <= n; j++)
            for (int i = n; i - (1 << j) + 1 >= 1; i--)
                f[i][j] = std::max(f[i][j - 1], f[i - (1 << (j - 1))][j - 1]);
        for (; m; m--) {
            int l, r;
            scanf("%d%d", &l, &r);
            int j = log2(r - l + 1);
            int ans = std::max(f[r][j], f[l + (1 << j) - 1][j]);
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    时间复杂度:预处理(O(nlogn)),查询(O(1))

    主席树

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int maxn = 2e5 + 5;
    int n, m, a[maxn], b[maxn];
    
    struct Node {int l, r, sum; Node(){l = r = sum = 0;}}z[maxn << 5];
    int cnt, root[maxn];
    
    template<class T>
    inline T read(T &x) {
        x = 0; int w = 1, ch = getchar();
        for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
        return x *= w;
    }
    
    void build(int &rt, int l, int r) {
        rt = ++cnt; if (l == r) return ;
        int mid = (l + r) >> 1;
        build(z[rt].l, l, mid), build(z[rt].r, mid + 1, r);
    }
    
    void modify(int &rt, int pre, int l, int r, int pos) {
        rt = ++cnt;
        z[rt].l = z[pre].l, z[rt].r = z[pre].r, z[rt].sum = z[pre].sum + 1;
        if (l == r) return ; int mid = (l + r) >> 1;
        if (pos <= mid) modify(z[rt].l, z[pre].l, l, mid, pos);
        else modify(z[rt].r, z[pre].r, mid + 1, r, pos);
    }
    
    int query(int L, int R, int l, int r, int pos) {
        if (l == r) return l; int mid = (l + r) >> 1;
        int temp = z[z[R].l].sum - z[z[L].l].sum;
        if (pos <= temp) return query(z[L].l, z[R].l, l, mid, pos);
        else return query(z[L].r, z[R].r, mid + 1, r, pos - temp);
    }
    
    int main() {
        read(n), read(m); int x, y, k;
        for (int i = 1; i <= n; i++) b[i] = read(a[i]);
        std::sort(b + 1, b + n + 1);
        int len = std::unique(b + 1, b + n + 1) - b - 1;
        build(root[0], 1, len);
        for (int i = 1; i <= n; i++) {
            int pos = std::lower_bound(b + 1, b + len + 1, a[i]) - b;
            modify(root[i], root[i - 1], 1, len, pos);
        }
        for (int i = 1; i <= m; i++) {
            read(x), read(y), read(k);
            printf("%d
    ", b[query(root[x - 1], root[y], 1, len, k)]);
        }
        return 0;
    }
    
    

    时间复杂度:(O(nlogn))

    FHQ Treap

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #define pii pair<int, int>
    
    using namespace std;
    
    const int maxn = 1e5 + 5;
    int w, ch;
    
    struct Node {
    	int key, val;
    	int ls, rs, size;
    }g[maxn];
    int root, cnt;
    
    template<class T>
    T read(T &x)
    {
    	x = 0, w = 1, ch = getchar();
    	while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48; ch = getchar();}
    	return x *= w;
    }
    
    void pushup(int p)
    {
    	g[p].size = g[g[p].ls].size + g[g[p].rs].size + 1;
    }
    
    void insert(int x)
    {
        ++cnt;
    	g[cnt].val = x;
    	g[cnt].size = 1;
    	g[cnt].key = rand();
    	g[cnt].ls = g[cnt].rs = 0;
    }
    
    int merge(int x, int y)
    {
    	if (x == 0) return y;
    	if (y == 0) return x;
    	if (g[x].key < g[y].key) {
    		g[x].rs = merge(g[x].rs, y);
    		pushup(x);
    		return x;
    	}
    	else {
    		g[y].ls = merge(x, g[y].ls);
    		pushup(y);
    		return y;
    	}
    }
    
    void split(int u, int x, int &l, int &r)
    {
    	if (!u) {l = r = 0; return;}
    	if (g[u].val <= x) {l = u; split(g[u].rs, x ,g[u].rs, r);}
    	else {r = u; split(g[u].ls, x, l, g[u].ls);}
    	pushup(u);
    }
    
    int rnk(int u, int num){
        if (num <= g[g[u].ls].size) {
        	int ret = rnk(g[u].ls, num);
        	return ret;
    	}	
        else{
            if (num == g[g[u].ls].size + 1) return u;
            else {
                num -= g[g[u].ls].size + 1;
                return rnk(g[u].rs, num);
            }
        }
    }
    
    int main()
    {
    	int n, temp, x, l, r;
    	read(n);
    	for (int i = 1; i <= n; i++) {
    		read(temp), read(x);
    		switch (temp) {
    			case 1:
    				split(root, x, l, r);
    				insert(x);
    				root = merge(merge(l, cnt), r);
    				break;
    			case 2:
    				int temp;
    				split(root, x, l, temp);
    				split(l, x - 1, l, r);;
    				r = merge(g[r].ls, g[r].rs);
    				root = merge(merge(l, r), temp);
    				break;
    			case 3:
    				split(root, x - 1, l, r);
    				printf("%d
    ", g[l].size + 1);
    				root = merge(l, r);
    				break;
    			case 4:
    				printf("%d
    ", g[rnk(root, x)].val);
    				break;
    			case 5:
    				split(root, x - 1, l, r);
    				printf("%d
    ", g[rnk(l, g[l].size)].val);
    				root = merge(l, r);
    				break;
    			case 6:
    				split(root, x, l, r);
    				printf("%d
    ", g[rnk(r, 1)].val);
    				root = merge(l, r);
    				break;
    		}
    	}
    	return 0;
    }
    

    时间复杂度:(O(nlogn))

    六·字符串算法

    KMP字符串匹配算法

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    const int maxn = 1e6 + 6;
    int kmp[maxn], j;
    char a[maxn], b[maxn];
    
    int main() {
        scanf("%s", a + 1); scanf("%s", b + 1);
        int lena = strlen(a + 1), lenb = strlen(b + 1);
        for (int i = 2; i <= lenb; i++) {
            while (j && b[i] != b[j + 1])
                j = kmp[j];
            if (b[i] == b[j + 1]) j++;
            kmp[i] = j;
        }
        j = 0;
        for (int i = 1; i <= lena; i++) {
            while (j && a[i] != b[j + 1])
                j = kmp[j];
            if (a[i] == b[j + 1]) j++;
            if (j == lenb) {printf("%d
    ", i - lenb + 1); j = kmp[j];}
        }
        for (int i = 1; i <= lenb; i++) printf("%d ", kmp[i]); puts("");
        return 0;
    }
    

    时间复杂度:(O(n+m))

    Manacher算法

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define max(a, b) ((a) > (b) ? (a) : (b))
    
    using std::string;
    const int maxn = 11000002;
    string x, s;
    int radius[maxn << 1], max_right, mid, ans;
    
    int main() {
        std::cin >> x;
        s += '&', s += '$';
        for (int i = 0; i < x.length(); i++) s += x[i], s += '$';
        for (int i = 1; i < s.length(); i++) {
            radius[i] = max_right > i ? min(radius[mid * 2 - i], max_right - i) : 1;
            while (s[i - radius[i]] == s[i + radius[i]]) radius[i]++;
            if (i + radius[i] > max_right) max_right = i + radius[i], mid = i;
            ans = max(ans, radius[i] - 1);
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    时间复杂度:(O(n))

    Trie树

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    
    const int maxn = 5e5 + 5;
    int n, m;
    
    struct Trie {
        int ch[maxn][26], siz;
        bool vis[maxn];
    
        Trie() {
            siz = 1;
            memset(ch[0], 0, sizeof(ch[0]));
            memset(vis, false, sizeof(vis));
        }
    
        void insert(char *s) {
            int root = 0, len = strlen(s + 1);
            for (int i = 1; i <= len; i++) {
                int ooo = s[i] - 'a';
                if (!ch[root][ooo]) {
                    memset(ch[siz], 0, sizeof(ch[siz]));
                    ch[root][ooo] = siz++;
                }
                root = ch[root][ooo];
            }
        }
    
        int search(char *s) {
            int root = 0, len = strlen(s + 1);
            for (int i = 1; i <= len; i++) {
                int ooo = s[i] - 'a';
                if (!ch[root][ooo]) return 0;
                root = ch[root][ooo];
            }
            if (!vis[root]) {
                vis[root] = true;
                return 1;
            }
            return 2;
        }
    }trie;
    
    signed main() {
        scanf("%lld", &n);
        char s[100];
        for (int i = 1; i <= n; i++) {
            scanf("%s", s + 1);
            trie.insert(s);
        }
        scanf("%lld", &m);
        for (int i = 1; i <= m; i++) {
            scanf("%s", s + 1);
            int ankh = trie.search(s);
            if (ankh == 0) puts("WRONG");
            else if (ankh == 1) puts("OK");
            else puts("REPEAT");
        }
        return 0;
    }
    

    总时间复杂度:(O(n * len))

    七·其它

    朴素高精度

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    
    using namespace std;
    const int maxn = 2005;
    
    struct BigNum {
        int d[maxn], len;
    
        void clean() {while (len > 1 && !d[len - 1]) len--;}
        BigNum() {memset(d, 0, sizeof(d)); len = 1;}
        BigNum(int num) {*this = num;}
        BigNum(char *num) {*this = num;}
    
        BigNum operator = (const char *num) {
            memset(d, 0, sizeof(d)), len = strlen(num);
            for (int i = 0; i < len; i++) d[i] = num[len - i - 1] - '0';
            clean();
            return *this;
        }
        BigNum operator = (int num) {
            char s[20]; sprintf(s, "%d", num);
            *this = s;
            return *this;
        }
    
        BigNum operator + (const BigNum &b) {
            BigNum c = *this; int i;
            for (i = 0; i < b.len; i++) {
                c.d[i] += b.d[i];
                if (c.d[i] > 9) c.d[i] %= 10, c.d[i + 1]++;
            }
            while (c.d[i] > 9) c.d[i++] %= 10, c.d[i]++;
            c.len = max(len, b.len);
            if (c.d[i] && c.len <= i) c.len = i + 1;
            return c;
        }
    
        BigNum operator - (const BigNum &b) {
            BigNum c = *this; int i;
            for (i = 0 ; i < b.len; i++) {
                c.d[i] -= b.d[i];
                if (c.d[i] < 0) c.d[i] += 10, c.d[i + 1]--;
            }
            while (c.d[i] < 0) c.d[i++] += 10, c.d[i]--;
            c.clean();
            return c;
        }
    
        BigNum operator * (const BigNum &b) const {
            BigNum c; int i, j; 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;
        }
    
        BigNum operator / (const BigNum &b) {
            int i, j;
            BigNum c = *this, last = 0;
            for (i = len - 1; i >= 0; i--) {
                last = last * 10 + d[i];
                for (j = 0 ; j < 10; j++) if (last < b * (j + 1)) break;
                c.d[i] = j;
                last = last - b * j;
            }
            c.clean();
            return c;
        }
    
        BigNum operator % (const BigNum &b) {
            int i, j;
            BigNum last = 0;
            for (i = len - 1; i >= 0; i--) {
                last = last * 10 + d[i];
                for (j = 0; j < 10; j++) if (last < b * (j + 1)) break;
                last = last - b * j;
            }
            return last;
        }
    
        bool operator < (const BigNum &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[maxn] = {};
            for (int i = 0; i < len; i++) s[len - i - 1] = d[i] + '0';
            return s;
        }
    };
    
    istream& operator >> (istream& in, BigNum &x) {
        string s;
        in >> s;
        x = s.c_str();
        return in;
    }
    
    ostream& operator << (ostream& out, const BigNum &x) {
        out << x.str();
        return out;
    }
    
    int main() {
        BigNum a, b;
        cin >> a >> b;
        cout << a + b << '
    ';
        return 0;
    }
    

    压位高精度

    // 受rainy大佬所教
    
    const int_t base = 100000000;
    
    void print(int_t x, int_t dig) {
    	if(!dig) return;
    	print(x / 10, dig - 1);
    	putchar(x % 10 + '0');
    }
    
    sturct BigInt {
    	int_t num[10], siz;
    	BigInt():siz(0){memset(num, 0, sizeof num);}
    	void operator !(){for(int_t i=0;i<siz;i++)if(num[i]>=base)siz=max(siz,i+2),num[i+1]+=num[i]/base,num[i]%=base;}
    	void operator +=(int_t x){num[0]+=x;!*this;}
    	void operator *=(int_t x){for(int_t i=0;i<siz;i++)num[i]*=x;!*this;}
    	void operator +=(BigInt x){siz=x.siz=max(siz, x.siz);for(int_t i=0;i<siz;i++)num[i]+=x[i];!*this;}
    	void operator ~(){printf("%lld",num[siz-1]);for(int_t i=siz-2;~i;i--)print(num[i],8);}
    };
    
    BigInt read() {
    	BigInt ans;
    	while(!isdigit(ch)) ch = getchar();
    	while(isdigit(ch)) ans *= 10, ans += ch - '0', ch = getch();
    	return ans;
    }
    
    int main() {
    	BigInt a; a += 100000000; 
    	a *= 123123123;
    	~a;
    }
    

    矩阵快速幂加速递推

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    
    using namespace std;
    
    const int MOD = 1e9 + 7;
    int n;
    
    struct Matrix {
        int a[4][4];
        Matrix(){memset(a, 0, sizeof(a));}
    }ans, base;
    
    Matrix operator * (const Matrix &x, const Matrix &y)
    {
        Matrix ret;
        for (int i = 1; i <= 2; i++)
            for (int j = 1; j <= 2; j++)
                for (int k = 1; k <= 2; k++)
                    ret.a[i][j] = (ret.a[i][j] + x.a[i][k] * y.a[k][j]) % MOD;
        return ret;
    }
    
    void init()
    {
        base.a[1][1] = base.a[1][2] = base.a[2][1] = 1;
        base.a[2][2] = 0;
        ans.a[1][1] = ans.a[1][2] = 1;
    }
    
    void quick_pow(int b)
    {
        while (b) {
            if (b & 1) ans = ans * base;
            base = base * base;
            b >>= 1;
        }
    }
    
    signed main()
    {
        init();
        scanf("%lld", &n);
        if (n <= 2) {puts("1"); return 0;}
        quick_pow(n - 2);
        printf("%lld
    ", ans.a[1][1]);
        return 0;
    }
    

    时间复杂度:快速幂(O(logn)),根据矩阵大小不同会带不同大小的常数

    大模拟

    猪国杀为例

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #define loves =
    
    using std::cin;
    using std::cout;
    using std::vector;
    using std::queue;
    using std::string;
    int n, m; // n -> 玩家数目 m -> 牌堆牌的数量
    int sf[12]; // 身份
    int lsf[12]; // 身份确定前的类身份
    int health[12]; // 血量
    bool crossbow[12]; // 猪哥连弩
    bool died[12]; // 是否已死
    vector<char>shoupai[12]; // 每只猪手牌
    queue<char>heap; //牌堆
    
    // ============card部分============
    char get_card() { // 牌堆里抽卡
        char ch = heap.front();
        heap.pop();
        if (heap.empty()) heap.push(ch);
        return ch;
    }
    
    void Erase_card(int rt, char ch) {
        for (auto it = shoupai[rt].begin(); it != shoupai[rt].end(); it++)
            if (*it == ch) {
                shoupai[rt].erase(it);
                return ;
            }
    }
    
    bool has_card(int rt, char ch) {
        for (auto it : shoupai[rt])
            if (it == ch) return true;
        return false;
    }
    // ============card部分============
    
    // ============读入部分============
    void input() {
        cin >> n >> m;
        for (int i =1 ; i <= n; i++) {
            string temp;
            cin >> temp; health[i] = 4;
            if (temp[0] == 'M' || temp[0] == 'Z') sf[i] = 1;
            else sf[i] = 2;
            for (int j = 1; j <= 4; j++) {
                char ch;
                cin >> ch;
                shoupai[i].push_back(ch);
            }
        }
        while (m--) {
            char ch;
            cin >> ch;
            heap.push(ch);
        }
    }
    // ============读入部分============
    
    // ============输出部分============
    void output() {
        int num_good = 0, num_bad = 0;
        for (int i = 1; i <= n; i++)
            if (!died[i])
                if (sf[i] == 1)
                    num_good++;
                else num_bad++;
        if (num_good && !died[1]) puts("MP");
        else puts("FP");
        for (int i = 1; i <= n; i++) {
            if (died[i]) puts("DEAD");
            else {
                for (auto it : shoupai[i]) cout << it << ' ';
                puts("");
            }
        }
        exit(0);
    }
    // ============输出部分============
    
    // ============无懈可击============
    bool can_WX(int fr, int rt, bool isWX) {
        // fr used WX for rt
        int nxt = fr;
        do {
            if (!died[nxt] && (isWX ? sf[nxt] != lsf[rt] : sf[nxt] == lsf[rt]) && has_card(nxt, 'J')) {
                Erase_card(nxt, 'J');
                lsf[nxt] = sf[nxt];
                if (can_WX(nxt, nxt, true))
                    return false;
                else return true;
            }
            ++nxt;
            if (nxt == n + 1) nxt = 1;
        } while (nxt != fr);
        return false;
    }
    // ============无懈可击============
    
    // ============掉血============
    void be_heart(int fr, int rt, bool jinnang) {
        health[rt]--;
        //std::cout << rt << "heart by" << fr << '
    ';
        if (rt == 1 && lsf[fr] == 0)
            lsf[fr] = 3;
        if (!jinnang && lsf[fr] && lsf[fr] != 3)
            lsf[fr] = sf[fr];
        if (health[rt]) return ;
        if (!health[rt] && has_card(rt, 'P')) {
            Erase_card(rt, 'P');
            ++health[rt];
        }
        else {
            died[rt] = true;
            if (rt == 1) output();
            int num_bad = 0;
            for (int i =1 ; i <= n; i++)
                if (!died[i])
                    if (sf[i] == 2) num_bad++;
            if (num_bad == 0) output();
            else {
                if (fr == 1 && sf[rt] == 1) {
                    shoupai[1].clear();
                    crossbow[1] = false;
                }
                if (sf[rt] == 2) {
                    shoupai[fr].push_back(get_card());
                    shoupai[fr].push_back(get_card());
                    shoupai[fr].push_back(get_card());
                }
            }
        }
    }
    // ============掉血============
    
    // ============南猪入侵============
    void use_NM(int rt) {
        int nxt = rt + 1;
        if (nxt == n + 1) nxt = 1;
        while (nxt != rt) {
            if (!died[nxt]) {
                if (can_WX(rt, nxt, false)) {
                    ++nxt;
                    if (nxt == n + 1) nxt = 1;
                    continue;
                }
                if (has_card(nxt, 'K'))
                    Erase_card(nxt, 'K');
                else {
                    be_heart(rt, nxt, true);
                    //std::cout << rt << "uesd NM hit" << nxt << "heart 1 滴血" << '
    ';
                }
            }
            ++nxt;
            if (nxt == n + 1) nxt = 1;
        }
    }
    // ============南猪入侵============
    
    // ============万箭齐发============
    void use_WJ(int rt) {
        int nxt = rt + 1;
        if (nxt == n + 1) nxt = 1;
        while (nxt != rt) {
            if (!died[nxt]) {
                if (can_WX(rt, nxt, false)) {
                    ++nxt;
                    if (nxt == n + 1) nxt = 1;
                    continue;
                }
                if (has_card(nxt, 'D'))
                    Erase_card(nxt, 'D');
                else {
                    be_heart(rt, nxt, true);
                    //std::cout << rt << "uesd WJ hit" << nxt << "heart 1 滴血" << '
    ';
                }
            }
            ++nxt;
            if (nxt == n + 1) nxt = 1;
        }
    }
    // ============万箭齐发============
    
    // ============决斗============
    void duel(int fr, int to) {
        if (!has_card(to, 'K') || (fr == 1 && sf[to] == 1)) {be_heart(fr, to, true); return ;}
        else {
            Erase_card(to, 'K');
            duel(to, fr);
        }
    }
    // ============决斗============
    
    // ============寻找下一个杀或决斗的目标============
    int Find(int rt, bool limit) {
        if (!limit && sf[rt] == 2) return 1;
        int nxt = rt + 1;
        if (nxt == n + 1) nxt = 1;
        while (nxt != rt) {
            //std::cout << "now find mubiao:" << nxt << '
    ';
            if (died[nxt]) {
                ++nxt;
                if (nxt == n + 1) nxt = 1;
                continue;
            }
            bool canhit = (rt == 1 ? lsf[nxt] >= 2 : lsf[nxt] != sf[rt]);
            if (rt > 1) {
                if (lsf[nxt] == 0 || lsf[nxt] == 3) canhit = false;
                else canhit = (lsf[nxt] != sf[rt]);
            }
            if (canhit) return nxt;
            else if (limit) return 0;
            ++nxt;
            if (nxt == n + 1) nxt = 1;
        }
        return 0;
    }
    // ============寻找下一个杀或决斗的目标============
    
    // ============游戏过程============
    void solve() {
        lsf[1] = 1;
         int rt = 0;
         while (true) {
            ++rt;
            if (rt == n + 1) rt = 1;
            if (died[rt]) continue;
            shoupai[rt].push_back(get_card());
            shoupai[rt].push_back(get_card());
            bool usedk = false;
            while (true) {
                if (died[rt]) break;
                bool usedcard = false;
                for (auto i = shoupai[rt].begin(); i != shoupai[rt].end(); i++) {
                    char it = *i;
                    if (it == 'P') {
                        if (health[rt] != 4) {
                            ++health[rt];
                            Erase_card(rt, 'P');
                            usedcard = true;
                            break;
                        }
                    }
                    else if (it == 'N'){
                        Erase_card(rt, 'N');
                        use_NM(rt);
                        usedcard = true;
                        break;
                    }
                    else if (it == 'W'){
                        Erase_card(rt, 'W');
                        use_WJ(rt);
                        usedcard = true;
                        break;
                    }
                    else if (it == 'Z') {
                        crossbow[rt] = true;
                        Erase_card(rt, 'Z');
                        usedcard = true;
                        break;
                    }
                    else if (it == 'K') {
                        if (usedk && !crossbow[rt]) continue;
                        int to = Find(rt, true);
                        if (!to) continue;
                        Erase_card(rt, 'K');
                        usedcard = usedk = true;
                        if (has_card(to, 'D')) {Erase_card(to, 'D'); ++health[to];}
                        be_heart(rt, to, false);
                        break;
                    }
                    else if (it == 'F') {
                        int to = Find(rt, false);
                        if (!to) continue;
                        lsf[rt] = sf[rt];
                        Erase_card(rt, 'F');
                        usedcard = true;
                        if (can_WX(rt, to, false)) break;
                        duel(rt, to);
                        usedcard = true;
                        break;
                    }
                }
                if (usedcard) continue;
                break;
            }
         }
    }
    // ============游戏过程============
    
    int haj() {
        input();
        solve();
        return 0;
    }
    
    int ziiidan loves haj();
    
    int main() {}
    
    

    大概……也许……就这些了吧……

    (CSP-S 2019) (RP++!!!)

  • 相关阅读:
    设计模式——桥接模式
    设计模式——工厂模式
    挖个坑
    Java 线程应用
    vtep-ctl + add-ls+ bind-ls +br-get-external-id
    ovs vtep 源码Tunnel_Ip
    vtep-ctl del-ls ls0
    vtep-ctl unbind-ls
    virt manager
    ironic 裸金属 failed to mount sysroot
  • 原文地址:https://www.cnblogs.com/Hydrogen-Helium/p/11833854.html
Copyright © 2020-2023  润新知