自己敲模板还是有很多容易错的地方
写在注释里面了
LCA
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int N = 5e5 + 10; //以后MAXN改成N。因为MAXM和MAXN不容易区分 const int M = 20; struct Edge{ int to, next; } e[N << 1]; int head[N], tot, n, m, s; int d[N], f[N][M + 10]; //注意这里一定一定是M+10 void AddEdge(int from, int to) { e[tot] = Edge{to, head[from]}; head[from] = tot++; } void dfs(int u, int fa) //dfs的作用是初始化f数组和d数组 { for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; d[v] = d[u] + 1; f[v][0] = u; dfs(v, u); } } void init() { f[s][0] = s; //注意这里一定是自己的父亲为自己 dfs(s, -1); _for(j, 1, M) //注意这里是到M,不是N _for(i, 1, n) f[i][j] = f[f[i][j-1]][j-1]; } int lca(int u, int v) { if(d[u] < d[v]) swap(u, v); //u和v不要写反 for(int j = M; j >= 0; j--) //逆序 if(d[f[u][j]] >= d[v]) //这里注意是深度的比较,u往上跳的深度和v本身的深度 u = f[u][j]; if(u == v) return u; for(int j = M; j >= 0; j--) if(f[u][j] != f[v][j]) u = f[u][j], v = f[v][j]; return f[u][0]; } int main() { memset(head, -1, sizeof(head)); tot = 0; scanf("%d%d%d", &n, &m, &s); REP(i, 1, n) { int u, v; scanf("%d%d", &u, &v); AddEdge(u, v); AddEdge(v, u); } init(); //主函数里面不要忘了写 _for(i, 1, m) { int u, v; scanf("%d%d", &u, &v); printf("%d ", lca(u, v)); } return 0; }
线段树
#include<bits/stdc++.h> #define ls (k << 1) #define rs (k << 1 | 1) #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; //根据题目 const int N = 2e5 + 10; struct Segment_Tree { int l, r; ll w, f; int m() { return (l + r) >> 1; } int len() { return r - l + 1; }; }t[N * 3]; int n, q; inline void deal(int k, ll p) { t[k].f += p; t[k].w += p * t[k].len(); } inline int up(int k) { t[k].w = t[ls].w + t[rs].w; } inline void down(int k) { deal(ls, t[k].f); deal(rs, t[k].f); t[k].f = 0; } void build(int k, int l, int r) { t[k] = Segment_Tree{l, r, 0, 0}; if(l == r) { scanf("%lld", &t[k].w); return; } int m = t[k].m(); build(ls, l, m); build(rs, m + 1, r); up(k); } void add(int k, int x, ll p) { if(t[k].l == t[k].r) //注意这里一定是这么写,不能写t[k].l == x,这是错的 { t[k].w += p; return; } if(t[k].f) down(k); int m = t[k].m(); if(x <= m) add(ls, x, p); else add(rs, x, p); up(k); } void change(int k, int L, int R, ll p) { if(L <= t[k].l && t[k].r <= R) { deal(k, p); return; } if(t[k].f) down(k); int m = t[k].m(); if(L <= m) change(ls, L, R, p); if(R > m) change(rs, L, R, p); up(k); } ll query(int k, int L, int R) { if(L <= t[k].l && t[k].r <= R) return t[k].w; if(t[k].f) down(k); int m = t[k].m(); ll res = 0; if(L <= m) res += query(ls, L, R); if(R > m) res += query(rs, L, R); return res; } int main() { scanf("%d", &n); build(1, 1, n); scanf("%d", &q); while(q--) { int op, x, y; ll z; scanf("%d", &op); if(op == 1) { scanf("%d%d%lld", &x, &y, &z); change(1, x, y, z); } else { scanf("%d%d", &x, &y); printf("%lld ", query(1, x, y)); } } return 0; }
KMP
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int N = 1e6 + 10; char a[N], b[N]; int next[N], lena, lenb; void get_next() { next[1] = 0; int j = 0; //注意这里从0开始。因为一开始匹配了0个 _for(i, 2, lenb) //这里的i从2开始 { while(j && b[j + 1] != b[i]) j = next[j]; if(b[j + 1] == b[i]) j++; next[i] = j; } } int main() { scanf("%s%s", a + 1, b + 1); lena = strlen(a + 1); lenb = strlen(b + 1); get_next(); int j = 0; _for(i, 1, lena) //这里的i从1开始 { while(j && b[j + 1] != a[i]) j = next[j]; if(b[j + 1] == a[i]) j++; if(j == lenb) { printf("%d %d ", i - lenb + 1, i); return 0; } } puts("NO"); return 0; }
同余方程
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll;//如果考到数论题一定要开longlong!!!!!!!! void exgcd(ll a, ll b, ll& d, ll& x, ll& y) { if(!b) { d = a; x = 1; y = 0; return; } else { exgcd(b, a % b, d, y, x); y -= x * (a / b); } } int main() { ll a, b, m; scanf("%lld%lld%lld", &a, &b, &m); ll A, B, K, d, x, y; A = a, B = -m, K = b; exgcd(A, B, d, x, y); if(K % d) { puts("no solution!"); return 0; } x *= K / d; int mod = abs(B / d); printf("%lld ", (x % mod + mod) % mod); return 0; }
同余方程组
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; void exgcd(ll a, ll b, ll& d, ll& x, ll& y) { if(!b) { d = a; x = 1; y = 0; return; } else { exgcd(b, a % b, d, y, x); y -= x * (a / b); } } int main() { int n; ll b1, b2, m1, m2; scanf("%d%lld%lld", &n, &b1, &m1); REP(i, 1, n) { scanf("%lld%lld", &b2, &m2); ll A, B, K, d, x, y; A = m1, B = -m2, K = b2 - b1; //推出什么写什么 exgcd(A, B, d, x, y); if(K % d) { puts("no solution!"); return 0; } x *= K / d; int mod = abs(B / d); //注意这里加abs x = (x % mod + mod) % mod; b1 = b1 + m1 * x; m1 = m1 * m2 / abs(d); //加abs } printf("%lld ", b1); return 0; }
欧拉函数
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; ll euler(ll x) { ll res = x; //注意区分res和x。x是用来取出因数的 for(int i = 2; i * i <= x; i++) if(x % i == 0) { res = res / i * (i - 1); //先除后乘比较保险,可以这么做是因为i是res的因数 while(x % i == 0) x /= i; } if(x > 1) res = res / x * (x - 1); return res; } int main() { int n; scanf("%d", &n); _for(i, 1, n) { ll x; scanf("%lld", &x); printf("%lld ", euler(x)); } return 0; }
//线性求法 const int N = 1e6 + 10; int euler[N]; void get_euler() { REP(i, 1, N) euler[i] = i; REP(i, 2, N) //注意这里i从2开始。 if(euler[i] == i) for(int j = i; j < N; j += i) euler[j] = euler[j] / i * (i - 1); }
线性筛素数
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int N = 2e7 + 10; bool is_prime[N]; vector<int> prime; void get_prime() { memset(is_prime, true, sizeof(is_prime)); is_prime[0] = is_prime[1] = false; REP(i, 2, N) //切记不能越界 { if(is_prime[i]) prime.push_back(i); REP(j, 0, prime.size()) { if(i * prime[j] >= N) break; //切记不能越界 is_prime[i * prime[j]] = false; if(i % prime[j] == 0) break; } } } int main() { get_prime(); int n; scanf("%d", &n); _for(i, 1, n) { int x; scanf("%d", &x); printf("%d ", prime[x-1]); } return 0; }
组合数
const int N = 1e3 + 10; int c[N][N]; void init() { REP(i, 0, N) //从0开始 { c[i][0] = 1; _for(j, 1, i) c[i][j] = c[i-1][j] + c[i-1][j-1]; } }
卡特兰数
f[1] = 1; REP(i, 2, N) f[i] = f[i-1] * (4 * i - 2) / (i + 1);