基础算法
倍增
int get(int l, int r) {
int d = r - l + 1;
int c = upper_bound(one, one + max_v + 1, d) - one - 1;
return max(dp[l][c], dp[r - one[c] + 1][c]);
// return min(dp[l][c], dp[r - one[c] + 1][c]);
}
void init() {
for (int i = 0; i <= max_v; i++) one[i] = 1 << i;
for (int d = 0; d <= max_v; d++) {
for (int i = 1; i <= n; i++) {
if (d == 0) dp[i][0] = a[i];
else {
int c = min(n, i + one[d - 1]);
dp[i][d] = max(dp[i][d - 1], dp[c][d - 1]);
// dp[i][d] = min(dp[i][d - 1], dp[c][d - 1]);
}
}
}
}
高精度
struct HAA{
vector<int> a;
int Mod = 0;
HAA(int x = 1, int _mod = 0) {
a.push_back(x), Mod = _mod;
}
HAA(vector<int> &b, int _mod = 0) {
a = b, Mod = _mod;
}
HAA operator + (const HAA &c) const {
vector<int> b;
int t = 0;
for (int i = 0; i < a.size() || i < c.a.size() || t; i++) {
if (i < a.size()) t += a[i];
if (i < c.a.size()) t += c.a[i];
b.push_back(t % 10);
t /= 10;
}
while (b.size() > 1 && b.back() == 0) b.pop_back();
return HAA(b);
}
HAA operator - (const HAA &c) const {
int t = 0;
vector<int> b;
for (int i = 0; i < a.size(); i++) {
t = a[i] - t;
if (i < c.a.size()) t -= c.a[i];
b.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}
while (b.size() > 1 && b.back() == 0) b.pop_back();
return HAA(b);
}
HAA operator / (const int &c) const {
int t = 0;
vector<int> b;
for (int i = (int)a.size() - 1; i >= 0; i--) {
t = t * 10 + a[i];
b.push_back(t / c);
t = t % c;
}
reverse(b.begin(), b.end());
while (b.size() > 1 && b.back() == 0) b.pop_back();
return HAA(b, t);
}
HAA operator * (const int &c) const {
int t = 0;
vector<int> b;
for (int i = 0; i < a.size() || t; i++) {
if (i < a.size())t += a[i] * c;
b.push_back(t % 10);
t /= 10;
}
while (b.back() == 0 && b.size() > 1) b.pop_back();
return HAA(b);
}
ll get_Mod() { return Mod; }
void print() {
for (int i = (int)a.size() - 1; i >= 0; i--) printf("%d", a[i]);
puts("");
}
static bool cmp(const HAA &a, const HAA &b) {
if (a.a.size() > b.a.size()) return true;
else if (a.a.size() < b.a.size()) return false;
for (int i = (int)a.a.size() - 1; i >= 0; i--) {
if (a.a[i] > b.a[i]) return true;
else if (a.a[i] < b.a[i]) return false;
}
return true;
}
};
搜索
双向广搜
// 内部
int extend(queue<string> &q, map<string, int> &da, map<string, int> &db) {
// 队列规则
return max + 1;
}
// 外部
int bfs(string x, string y) {
queue<string> qa, qb;
map<string, int> da, db;
da[x] = 0, qa.push(x);
db[y] = 0, qb.push(y);
while (qa.size() && qb.size()) {
int t;
if (qa.size() <= qb.size())t = extend(qa, da, db);
else t = extend(qb, db, da);
if (t <= max) return t;
}
// max为最大限制
return max;
}
欧拉回路
// 此模板用于解决一笔画问题,并记录路径。
void dfs(int u) {
for (int &i = h[u], t; ~i;) {
int j = e[i];
if (st[i]) {
i = ne[i]; //引用改变h[u]的值
continue;
}
st[i] = true;
i = ne[i];// h[u]删去以遍历的边,需要放在dfs前
dfs(j);
ans[++cnt] = t;
}
}
数据结构
splay
// 将x这个点往上翻转
void rotate(int x) {
int y = tr[x].p, z = tr[y].p;
int k = tr[y].s[1] == x;
tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
tr[x].s[k ^ 1] = y, tr[y].p = x;
pushup(y), pushup(x);
}
// 将x翻转到k的下方
void splay(int x, int k) {
while (tr[x].p != k) {
int y = tr[x].p, z = tr[y].p;
if (k != z) {
if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y))rotate(x);
else rotate(y);
}
rotate(x);
}
if (!k)root = x;
}
// 按照权值大小插入某个值保证单调性
void insert(int v) {
int u = root, p = 0;
// p为当前节点,u为需要放到的位置节点
while (u != 0)p = u, u = tr[u].s[v > tr[u].v];
u = ++idx;
if (p)tr[p].s[v > tr[p].v] = u;
tr[u].init(v, p);
splay(u, 0);
}
主席树
// 结构体
struct node{
int l, r;
// int cnt;
}tr[N * 4 + N * 17];
// 哨兵,最开始未修改的线段树
int build(int l, int r) {
int p = ++idx;
if (l == r) {
return p;
}
int mid = l + r >> 1;
tr[p].l = build(l, mid);
tr[p].r = build(mid + 1, r);
return p;
}
// 插入最新版本的线段树,是从q那个版本转移而来
int insert(int q, int l, int r, int x) {
int p = ++idx;
tr[p] = tr[q];
if (l == r) {
tr[p].cnt++;
return p;
}
int mid = l + r >> 1;
if (x <= mid) tr[p].l = insert(tr[q].l, l, mid, x);
else tr[p].r = insert(tr[q].r, mid + 1, r, x);
push_up(p);
return p;
}
// 查询l ~ r之间构成的线段树
int query(int p, int q, int l, int r, int k) {
if (l == r) return vec[l];
int mid = l + r >> 1;
// 线段树操作
// int d = tr[tr[p].l].cnt - tr[tr[q].l].cnt;
// if (d >= k) return query(tr[p].l, tr[q].l, l, mid, k);
// return query(tr[p].r, tr[q].r, mid + 1, r, k - d);
}
字符串
KMP
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=1e6+5;
char p[N], s[M];
int ne[N];
int n, m;
int main() {
cin >> n >> p + 1 >> m >> s + 1;
for(int i=2,j=0;i<=n;i++) {
while (j && t[i] != t[j + 1])j = ne[j];
if (t[j + 1] == t[i])j++;
ne[i] = j;
while (ne[i] && t[i + 1] == t[ne[i] + 1]) ne[i] = ne[j];
}
for (int i = 1, j = 0; i <= m; i++) {
while (j && s[i] != p[j + 1])j = ne[j];
if (s[i] == p[j + 1])j++;
if (j == n) {
printf("%d ", i - n);
j = ne[j];
}
}
return 0;
}
字符串哈希
#include "iostream"
#include "cstdio"
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5 + 5, P = 131;
char str[N];
ULL h[N], p[N];
// 获取字符串哈希
ULL get(int l,int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
// 初始化
int n;
scanf("%d", &n);
scanf("%s", str);
p[0] = 1;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + str[i - 1];
}
return 0;
}
AC自动机
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e4 + 5, M = 1e6 + 5;
char s[M];
int p[N * 50][26];
int cnt[N * 50];
int ne[N * 50], n, idx;
// insert建立字典树
void insert() {
int m = strlen(s), q = 0;
for (int i = 0; i < m; i++) {
int t = s[i] - 'a';
if (!p[q][t]) p[q][t] = ++idx;
q = p[q][t];
}
cnt[q]++;
}
// 通过字典树更新ne数组
void build() {
queue<int> que;
int q = 0;
for (int i = 0; i < 26; i++) {
if (p[q][i]) que.push(p[q][i]);
}
while (que.size()) {
int u = que.front();
que.pop();
for (int i = 0; i < 26; i++) {
int c = p[u][i];
if (!c) p[u][i] = p[ne[u]][i];
else {
ne[c] = p[ne[u]][i];
que.push(c);
}
}
}
}
int main() {
scanf("%d", &n);
while (n--) {
scanf("%s", s);
insert();
}
build();
scanf("%s", s + 1);
m = strlen(s + 1);
int res = 0;
for (int i = 1, j = 0; i <= m; i++) {
int t = s[i] - 'a';
j = p[j][t];
int q = j;
while (q) {
res += cnt[q];
cnt[q] = 0;
q = ne[q];
}
}
printf("%d\n", res);
return 0;
}
数学
欧拉降幂
\( A^K(mod\ m)= \begin{cases} A^{K\%\phi(m)},&m,A互质\\ A^{K\%\phi(m)+\phi(m)},&K\geqslant\phi(m)\\ A^{K} &K<\phi(m)\\ \end{cases} \)
数列求和公式
- 平方和求和:\(\sum_{k=1}^{n}k^2=\frac{n(n+1)(n+2)}{6}\)
组合数公式
- 杨辉恒等式: \(C(n,k)=C(n−1,k)+C(n−1,k−1)\)
- 对称性:\(C(n,k)=C(n,n−k)\)
- 单行和:\(\sum_{i=0}^{n}C(n,i)=2^n\)
- 单行平方和:\(\sum_{i=0}^{n}C(n,i)^2=C(2n,n)\)
- 斜60行和=反斜下一行对应值:\(\sum_{i=0}^{n}C(k+i,k)=C(k+n+1,k+1)\)
- 30∘ 斜行和等于Fibonacci数列:
- 递推式:\(C(n,i)=\frac{(n+1-i)}i*C(n,i-1)\)
- 求组合数某一段的和:\(\sum_{i=a}^{b}C(i,j)=C(b+1,j+1)-C(a,j+1)\)
- \(C(n,m)\)的奇偶性:n&m=m为奇,否则为偶(lucas定理推论)
- 卡特兰数:
- \(\frac{C(2n,n)}{n+1}\)
- \(C(n+m,n)-C(n+m,n-1)\)
- \(\frac{C(n+m,n)*(m+1-n)}{m+1}\)
整除分块:\(n/(n/x)\)
// 两个数的整除分块
for (int l = 1, r; l <= R; l = r + 1) {
r = L / l ? min(L / (L / l), R / (R / l)) : R / (R / l);
}
// 一个数的整除分块
for (int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
}
扩展欧几里得
ll extend(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
ll t = extend(b, a % b, y, x);
y -= a / b * x;
return t;
}
乘法逆元:\(P=P*\lfloor{\frac{P}{i}}\rfloor+P\%i\)
for(int i = 2; i <= n; i++) {
inv[i] = (-inv[p % i] * (p / i)) % p + p;
}
莫比乌斯反演
- 反演一:\(f(n)=\sum_{d|n} g(d), g(n)=\sum_{d|n}μ(\frac{n}{d})*f(d)\)。
- 反演二:\(f(d)=\sum_{d|n} g(n), g(d)=\sum_{d|n}μ(\frac{n}{d})*f(n)\)。
void init(int n) { // 欧拉筛模板
mobius[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) p[idx++] = i, mobius[i] = -1;
for (int j = 0; p[j] <= n / i; j++) {
st[i * p[j]] = true;
if (i % p[j] == 0) break;
mobius[i * p[j]] = mobius[i] * -1;
}
}
}
- \(M[n]=\sum_{i=1}^nμ[i]\)
- \(M[n]=1-\sum_{i=2}^nM[\lfloor{\frac{n}{i}}\rfloor]\)
ll Djs(int n) { // 杜教筛模板
if (n < N) return mobius[n];
if (mp.count(n)) return mp[n];
int ans = 1;
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
ans = (ans - 1ll * (r - l + 1) * Djs(n / l) % mod + mod) % mod;
}
return mp[n] = ans;
}
矩阵
struct Matrix{ // 矩阵模板
int a[M][M];
Matrix(int x = 0) {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
if (i == j) a[i][i] = x;
else a[i][i] = 0;
}
}
}
Matrix operator * (const Matrix &that) const {
Matrix ret;
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
for (int k = 0; k < M; k++) {
ret.a[i][j] = limit(ret.a[i][j] + (ll)this->a[i][k] * that.a[k][j]);
}
}
}
return ret;
}
Matrix operator + (const Matrix &that) const {
Matrix ret;
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
ret.a[i][j] = limit((ll)this->a[i][j] + that.a[i][j]);
}
}
return ret;
}
static ll limit(ll x) {
if (x >= mod) return x % mod;
return x;
}
void qsm(ll b) {
Matrix E;
// 给需要快速幂的矩阵赋值.
while (b) {
if (b & 1) *(this) = E * (*this);
E = E * E;
b >>= 1;
}
}
};
生成函数
形式幂级数常见的逆:
- 常生成函数:\(A(x)B(x)=1\)
- \(A(x)=\sum_{i=0}x^i\),\(B(x)=1-x\)
- \(A(x)=\sum_{i=0}(ax)^i\),\(B(x)=1-ax\)
- \(A(x)=\sum_{n=0}C^{k-1}_{n+k-1}x^n\),\(B(x)=(1-x)^k\)
- \(A(x)=\sum_{i=0}f(x)^i\),\(B(x)=1-f(x)\)
- 指数生成函数:
- \(exp(x)=\sum_{n>=0}\frac{x^n}{n!}\)
- \(exp(ax)=\sum_{n>=0}{\frac{(ax)^n}{n!}}\)
- \(\frac{exp(x)+exp(-x)}{2}=\sum_{2|i}\frac{x^i}{i!}\)
欧拉定理
\(a+bi=re^{i\theta},r=\sqrt{a^2+b^2},tan(\theta)=\frac{b}{a}\)
单位根:
\(\omega^n=1,\omega^k=e^{i\frac{2k\pi}{n}}\)
常见性质:
- \(\omega_{n}^k=\omega_{2k}^{2n}\)
- \(\omega_{2n}^{k+n}=-\omega_{2n}^{k}\)
DFT & IDFT
- \(\Omega{ij}=\omega^{ij}_{n},\Omega{ij}=\omega^{-ij}_{n}\)
- 系数矩阵:\(A=(a_0,a_1,...,a_n)\)
- 点值矩阵:\(B=(b_0,b_1,...,b_n)\)
- \(\Omega{A}=B,A=\frac{1}{n}\Omega^{-1}B\)
递归版
#include <cmath>
#include <complex>
typedef std::complex<double> Comp; // STL complex
const Comp I(0, 1); // i
const int MAX_N = 1 << 20;
const double PI = acos(-1);
Comp tmp[MAX_N];
// rev=1,DFT; rev=-1,IDFT
void DFT(Comp* f, int n, int rev) {
if (n == 1) return;
for (int i = 0; i < n; ++i) tmp[i] = f[i];
// 偶数放左边,奇数放右边
for (int i = 0; i < n; ++i) {
if (i & 1)
f[n / 2 + i / 2] = tmp[i];
else
f[i / 2] = tmp[i];
}
Comp *g = f, *h = f + n / 2;
// 递归 DFT
DFT(g, n / 2, rev), DFT(h, n / 2, rev);
// cur 是当前单位复根,对于 k = 0 而言,它对应的单位复根 omega^0_n = 1。
// step 是两个单位复根的差,即满足 omega^k_n = step*omega^{k-1}*n,
// 定义等价于 exp(I*(2*M_PI/n*rev))
Comp cur(1, 0), step(cos(2 * PI / n), sin(2 * PI * rev / n));
for (int k = 0; k < n / 2;
++k) { // F(omega^k_n) = G(omega^k*{n/2}) + omega^k*n\*H(omega^k*{n/2})
tmp[k] = g[k] + cur * h[k];
// F(omega^{k+n/2}*n) = G(omega^k*{n/2}) - omega^k_n*H(omega^k\_{n/2})
tmp[k + n / 2] = g[k] - cur * h[k];
cur *= step;
}
for (int i = 0; i < n; ++i) f[i] = tmp[i];
}
非递归版
struct Complex {
double x, y;
Complex(double _x = 0.0, double _y = 0.0) {
x = _x, y = _y;
}
Complex operator-(const Complex &b) const {
return Complex(x - b.x, y - b.y);
}
Complex operator+(const Complex &b) const {
return Complex(x + b.x, y + b.y);
}
Complex operator*(const Complex &b) const {
return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
}
};
void change(Complex y[], int len) {
int k;
for (int i = 1, j = len / 2; i < len - 1; i++) {
if (i < j) std::swap(y[i], y[j]);
k = len / 2;
while (j >= k) {
j = j - k;
k = k / 2;
}
if (j < k) j += k;
}
}
// on == 1 时是 DFT,on == -1 时是 IDFT
void fft(Complex y[], int len, int on) {
change(y, len);
for (int h = 2; h <= len; h <<= 1) {
Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));
for (int j = 0; j < len; j += h) {
Complex w(1, 0);
for (int k = j; k < j + h / 2; k++) {
Complex u = y[k];
Complex t = w * y[k + h / 2];
y[k] = u + t;
y[k + h / 2] = u - t;
w = w * wn;
}
}
}
if (on == -1) {
for (int i = 0; i < len; i++) {
y[i].x /= len;
y[i].x += 0.5;
}
}
}
图论
网络流
// dinic
void add(int a, int b, int c, int d) {
e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx++;
e[idx] = a, ne[idx] = h[b], f[idx] = d, h[b] = idx++;
}
bool bfs() {
memset(d, -1, sizeof(d));
queue<int> que;
que.push(S), d[S] = 0, cur[S] = h[S];
while (!que.empty()) {
int u = que.front(); que.pop();
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (d[j] == -1 && f[i]) {
d[j] = d[u] + 1;
cur[j] = h[j];
if (j == T) return true;
que.push(j);
}
}
}
return false;
}
int find(int u, int limit) {
if (u == T) return limit;
int flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {
cur[u] = i;
int j = e[i];
if (d[j] == d[u] + 1 && f[i]) {
int t = find(j, min(f[i], limit - flow));
if (!t) d[j] = -1;
f[i] -= t, f[i ^ 1] += t, flow += t;
}
}
return flow;
}
int dinic() {
int res = 0, flow;
while (bfs()) while (flow = find(S, INF)) res += flow;
return res;
}
有向图的强连通分量
void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
stk.push(u), st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j);
low[u] = min(low[u], low[j]);
} else if (st[j])low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u]) {
++scc_cnt;
while (true) {
int v = stk.top();
stk.pop();
scc[v] = scc_cnt, st[v] = false, sum[scc_cnt]++;
if (u == v)break;
}
}
}
无向图的强连通分量
- 无向连通图中,如果删除某点后,图变成不连通,则称该点为割点
- 无向连通图中,如果删除某边后,图变成不连通,则称该边为桥
void tarjan(int u, int fa) {
dfn[u] = low[u] = ++cnt;
stk.push(u);
// int child = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j, i);
low[u] = min(low[u], low[j]);
// i和i^1为割边
// if (dfn[u] < low[j]) st[i] = st[i ^ 1] = true;
// u是割点
// if (dfn[u] <= low[j]) {
// child++;
// if (u != root || child > 1) st[u] = true;
// }
} else if (fa != (i ^ 1)) {
low[u] = min(low[u], dfn[j]);
}
}
if (dfn[u] == low[u]) {
++scc_cnt;
while (true) {
int v = stk.top();
stk.pop();
scc[v] = scc_cnt;
if (u == v)break;
}
}
}
lca
void bfs() {
memset(depth, 0x3f, sizeof(depth));
depth[0] = 0, depth[root] = 1;
queue<int> que;
que.push(root);
while (que.size()) {
int u = que.front();
que.pop();
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (depth[j] > depth[u] + 1) {
depth[j] = depth[u] + 1;
que.push(j);
fa[j][0] = u;
for (int k = 1; k <= max_v; k++) {
fa[j][k] = fa[fa[j][k - 1]][k - 1];
}
}
}
}
}
int lca(int a,int b) {
if (depth[a] < depth[b]) swap(a, b);
for (int k = max_v; k >= 0; k--) {
if (depth[fa[a][k]] >= depth[b])
a = fa[a][k];
}
if (a == b)return a;
for (int k = max_v; k >= 0; k--) {
if (fa[a][k] != fa[b][k]) {
a = fa[a][k];
b = fa[b][k];
}
}
return fa[a][0];
}
计算几何
求某个点在三角形内部
#include <iostream>
#include <math.h>
using namespace std;
struct Point {
double x;
double y;
};
double product(Point p1,Point p2,Point p3) {
//首先根据坐标计算p1p2和p1p3的向量,然后再计算叉乘
//p1p2 向量表示为 (p2.x-p1.x,p2.y-p1.y)
//p1p3 向量表示为 (p3.x-p1.x,p3.y-p1.y)
return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x);
}
bool isInTriangle(Point p1,Point p2,Point p3,Point o) {
//保证p1,p2,p3是逆时针顺序
if(product(p1, p2, p3)<0) return isInTriangle(p1,p3,p2,o);
if(product(p1, p2, o)>0 && product(p2, p3, o)>0 && product(p3, p1, o)>0)
return true;
return false;
}
int main() {
Point p1,p2,p3,o;
cin >> p1.x >> p1.y;
cin >> p2.x >> p2.y;
cin >> p3.x >> p3.y;
cin >> o.x >> o.y;
bool flag = isInTriangle(p1,p2,p3,o);
if(flag) puts("Yes");
else puts("No");
}
标签:return,int,tr,++,算法,const,模板,size
From: https://www.cnblogs.com/syf2020/p/16655567.html