T // 样例数 a b c // 单变量 x y z // for循环索引 i j k // 比较少用到 u v w // 节点和权重 n m // 节点个数/数组大小一类 l r // 左右边界 s // 字符串 q // 队列 st // 栈 ch // 字符 s[MAXN] // 数组 vis[MAXN] // 图论 是否到达过 e[MAXN] // 图论 边 t[MAXN] // 树(偶尔用) d[MAXN] // 距离,或表示权重 dp[MAXN] // 动态规划 vector <int> g[MAXN] // 图论(邻接表)
tf // bool判断 ans // 答案 inp // 纯输入用 cnt // 计数 dis // 距离 tmp // 临时存储 MOD // 取模大数 maxn minn // 最大最小值
boolhalfCheck(int mid, int a) { return s[mid] >= a; }
intbinarySearch(int l, int r, int a) { int re; while(l <= r) { int mid = (l + r) >> 1; if(halfCheck(mid, a)) { r = mid - 1; re = mid; } else l = mid + 1; } return re; }
快速排序
不会真的有人不用STL的sort,还自己写快排吧(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
int s[MAXN];
voidfastSort(int l, int r) { if(l >= r) return; int i = l, j = r; while(i < j) { while(s[j] >= s[l] && i < j) j--; while(s[i] <= s[l] && i < j) i++; swap(s[i], s[j]); } swap(s[l], s[i]); fastSort(l, i - 1); fastSort(i + 1, r); }
数学
快速幂
可以在$O(\log n)$的时间复杂度里求出$a^n\ \text{mod}\ m$
1 2 3 4 5 6 7 8 9 10
LL fastPow(LL a, LL n, LL m)// 一般要开long long { LL ans = 1; while(n) { if(n & 1) ans *= a, ans %= m; a *= a, a %= m, n >>= 1; } return ans % m; }
GCD 欧几里得算法
求a和b的最大公约数
1 2 3 4 5
intgcd(int a, int b) { if(!b) return a; elsereturngcd(b, a % b); }
EXGCD 扩展欧几里得算法
在求得a、b的最大公约数的同时,能找到整数x、y,满足贝祖等式 $$ax + by = \gcd(a, b)$$
1 2 3 4 5
voidexgcd(int a, int b, int &x, int &y) { if(!b) x = 1, y = 0; elseexgcd(b, a % b, y, x), y -= a / b * x; }
逆元
用$O(n)$的时间求1到n对模m的逆元 $$ax \equiv 1 \pmod{m}$$
1 2 3 4
int n, m, inv[MAXN];
inv[1] = 1; for(int x = 2; x <= n; x++) inv[x] = (inv[m % x] * (m-m/x)) % m;
中国剩余定理
用于解以下一元线性同余方程组 $$ \begin{cases} x \equiv a_1 \pmod{m_1} \\ x \equiv a_2 \pmod{m_2} \\ \ \ \ \vdots \\ x \equiv a_n \pmod{m_n} \end{cases} $$ 注意配合前面的exgcd使用 考虑到实际情况一般答案会很大,建议开long long
1 2 3 4 5 6 7 8 9 10 11 12
intCRT(int n, int *a, int *m) { int N = 1, ans = 0; for(int x = 1; x <= n; x++) N *= a[x]; for(int x = 1; x <= n; x++) { int b = N / a[x], ny, tmp; exgcd(b, a[x], ny, tmp); ans = (ans + b * (ny < 0 ? ny + a[x] : ny) * m[x]) % N; } return ans; }
voidFloyd() { findN = false; for(int z = 1; z <= n; z++) for(int x = 1; x <= n; x++) for(int y = 1; y <= n; y++) if(d[x][z] < INF && d[z][y] < INF) d[x][y] = min(d[x][y], d[x][z] + d[z][y]); for(int x = 1; x <= n; x++) if(d[x][x] < 0) findN = true; // 找到负环 }
然后main函数里要这样子初始化以及读边
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intmain() { cin >> n >> m; for(int x = 0; x < n; x++) for(int y = 0; y < n; y++) d[x][y] = (x == y ? 0 : INF); for(int x = 1; x <= m; x++) { int u, v, w; cin >> u >> v >> w; d[u][v] = min(d[u][v], w); } }
intfind(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
intKruskal() { for(int x = 1; x <= n; x++) fa[x] = x; int ans = 0; sort(g+1, g+m+1, cmp); for(int x = 1; x <= m; x++) { int u = find(g[x].u), v = find(g[x].v); if(u == v) continue; fa[v] = u; ans += g[x].w; MST.push_back(g[x]); } return ans; }
int n, m, cnt, colcnt; vector <int> g[MAXN]; int dfn[MAXN], low[MAXN], color[MAXN]; bool vis[MAXN]; stack <int> st;
voidTarjan(int u) { dfn[u] = low[u] = ++cnt; st.push(u); vis[u] = true; for(int x = 0; x < g[u].size(); x++) { int v = g[u][x]; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } elseif(vis[v]) low[u] = min(low[u], dfn[v]); // 找到环了 } if(dfn[u] == low[u]) { colcnt++; int v; do { v = st.top(); st.pop(); vis[v] = false; color[v] = colcnt; // 染色 } while(v != u); } }
vector <int> ng[MAXN];
voidnewGraph()// 用颜色建新图 { for(int x = 0; x < n; x++) for(int y = 0; y < g[x].size(); y++) { int v = g[x][y]; if(color[x] != color[v]) ng[color[x]].push_back(color[v]); } }
intgetLCA(int a, int b) { if(dep[a] < dep[b]) swap(a, b); for (int i = 19; i >= 0; i--) if (dep[a] - (1 << i) >= dep[b]) a = fa[a][i]; if(a == b) return a; for(int x = lg[dep[a]]; x >= 0; x--) if(fa[a][x] != fa[b][x]) a = fa[a][x], b = fa[b][x]; return fa[a][0]; }
int n, m; vector <node> g[MAXN]; int dist[MAXN], prevv[MAXN], preve[MAXN]; bool vis[MAXN];
voidaddEdge(int u, int v, int cap, int cost) { g[u].push_back((node){v, (int)g[v].size(), cap, cost}); g[v].push_back((node){u, (int)g[u].size()-1, 0, -cost}); // 反向边 }
boolSPFA(int st, int ed) { for(int x = 0; x < n; x++) dist[x] = INF, vis[x] = false; // 注意下标 dist[st] = 0; queue <int> q; q.push(st); vis[st] = true; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int x = 0; x < g[u].size(); x++) { int v = g[u][x].v, cap = g[u][x].cap, cost = g[u][x].cost; if(cap > 0 && dist[v] > dist[u] + cost) { dist[v] = dist[u] + cost; prevv[v] = u; preve[v] = x; if(!vis[v]) { q.push(v); vis[v] = true; } } } } return dist[ed] < INF; }
reNode minCostMaxFlow(int st, int ed) { int flow = 0, cost = 0; while(SPFA(st, ed)) { int f = INF; for(int u = ed; u != st; u = prevv[u]) f = min(f, g[prevv[u]][preve[u]].cap); flow += f; cost += f * dist[ed]; for(int u = ed; u != st; u = prevv[u]) { g[prevv[u]][preve[u]].cap -= f; g[u][g[prevv[u]][preve[u]].rev].cap += f; } } return (reNode){flow, cost}; }
intminCost(int st, int ed, int F) { int flow = 0, cost = 0; while(F > 0 && SPFA(st, ed)) { int f = F; for(int u = ed; u != st; u = prevv[u]) f = min(f, g[prevv[u]][preve[u]].cap); F -= f; flow += f; cost += f * dist[ed]; for(int u = ed; u != st; u = prevv[u]) { g[prevv[u]][preve[u]].cap -= f; g[u][g[prevv[u]][preve[u]].rev].cap += f; } } return F > 0 ? -1 : cost; }
voidbuildBiGraph() { cin >> n1 >> n2 >> m; n = n1 + n2 + 2; S = n1 + n2; T = S + 1; for(int x = 1; x <= m; x++) { int u, v; cin >> u >> v; addEdge(u, v+n1, 1); } for(int x = 0; x < n1; x++) addEdge(S, x, 1); for(int x = 0; x < n2; x++) addEdge(x+n1, T, 1); }
intbiMatchNum() { returnDinic(S, T); // 最大匹配边数 }
structedge { int u, v; };
vector <edge> biMatchEdge() // 基于残量网络找匹配边 { vector <edge> re; for(int u = 0; u < n1; u++) { for(int x = 0; x < g[u].size(); x++) { int v = g[u][x].v, cap = g[u][x].cap; if(v >= n1 && v < n1 + n2 && cap == 0) re.push_back((edge){u, v-n1}); } } return re; }
#define MOD 1000007 //可以根据数据范围调整 intgetHash(string s, int BASE) { int l = s.size(), re = 0; for(int x = 0; x < l; x++) re = (re*BASE+int(s[x])) % MOD; return re; }