模版代码
序
这 \(1600\) 行代码收录着大部分提高级算法.
这 \(1600\) 行代码埋葬着一位 OIer 的青春.
代码均经 vscode 默认格式化,少量带*的算法为NOI级内容.
也曾想学过太多,但只留下了遗憾与力不从心.
最后修改于 2025.11.28
数据结构
1.ST表
struct SparseTable
{
int f[T][N];
void reset(int n, int *a)
{
for (int i = 1; i <= n; ++i)
f[0][i] = a[i];
for (int i = 1; i < T; ++i)
for (int j = 1, l = 1 << i; j < l - 1 <= n; ++j)
f[i][j] = max(f[i - 1][j], f[i - 1][j + (l >> 1)]);
}
int query(int l, int r)
{
int k = log2(r - l + 1);
return max(f[k][l], f[k][r - (1 << k) + 1]);
}
};
2.并查集
- 普通并查集
struct DisjointSetUnion
{
int par[N];
void reset(int n)
{
for (int i = 1; i <= n; ++i)
par[i] = i;
}
int find(int u)
{
return par[u] == u ? u : par[u] = find(par[u]);
}
void merge(int u, int v)
{
u = find(u), v = find(v);
par[u] = v;
}
};
- 带权并查集
struct DisjointSetUnion
{
int par[N], val[N];
void reset(int n)
{
for (int i = 1; i <= n; ++i)
par[i] = i, val[i] = 0;
}
int find(int u)
{
if (par[u] == u)
return u;
int root = find(par[u]);
val[u] += val[par[u]];
return par[u] = root;
}
void merge(int u, int v, int w)
{
int fu = find(u), fv = find(v);
par[fu] = fv, val[fu] = w + val[v] - val[u];
}
};
- 可撤销并查集
struct DisjointSetUnion
{
int par[N], siz[N];
stack<pair<int, int>> his;
void reset(int n)
{
for (int i = 1; i <= n; ++i)
par[i] = i, siz[i] = 0;
}
int find(int u)
{
return par[u] == u ? u : find(par[u]);
}
void merge(int u, int v)
{
u = find(u), v = find(v);
if(u == v) return;
if (siz[u] > siz[v])
swap(u, v);
his.push({u, siz[u]});
par[u] = v, siz[v] += siz[u];
}
void undo(int tim)
{
while (his.size() > tim)
{
int u = his.top().first;
int w = his.top().second;
his.pop();
siz[par[u]] -= w, par[u] = u;
}
}
};
3.树状数组
- 普通树状树组
struct BitIndexTree
{
int tr[N];
void modify(int x, int d)
{
for (; x <= n; x += x & -x)
tr[x] += d;
}
int query(int x)
{
int sum = 0;
for (; x; x -= x & -x)
sum += tr[x];
return sum;
}
};
- 区间加区间和树状树组
\[s_r=(r+1)\sum\limits_{i=1}^rd_i-\sum\limits_{i=1}^r{i \times d_i}
\]
struct BitIndexTree
{
int tr[2][N];
void _modify(int k, int x, int d)
{
for (; x <= n; x += x & -x)
tr[k][x] += d;
}
int _query(int k, int x)
{
int sum = 0;
for (; x; x -= x & -x)
sum += tr[k][x];
return sum;
}
void modify(int l, int r, int d)
{
_modify(0, l, d);
_modify(0, r + 1, -d);
_modify(1, l, l * d);
_modify(1, r + 1, -(r + 1) * d);
}
int query(int l, int r)
{
return ((r + 1) * _query(0, r) - _query(1, r)) -
(l * _query(0, l - 1) - _query(1, l - 1));
}
};
- 二维树状树组
struct BitIndexTree
{
int tr[N][N];
void modify(int x, int y, int d)
{
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= n; j += j & -j)
tr[i][j] += d;
}
int query(int x, int y)
{
int sum = 0;
for (int i = x; i; i -= i & -i)
for (int j = y; j; j -= j & -j)
sum += tr[i][j];
return sum;
}
};
4.线段树
- 普通线段树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
#define mid ((s + t) >> 1)
struct Node
{
int v;
} tr[N << 2];
void build(int p, int s, int t)
{
v(p) = 0;
if (s == t)
return;
build(ls(p), s, mid);
build(rs(p), mid + 1, t);
}
void pushUp(int p)
{
// v(p) = ...
}
void modify(int p, int s, int t, int x, int d)
{
if (x < s || t < x)
return;
if (s == t)
{
// v(p) = ...
return;
}
modify(ls(p), s, mid, x, d);
modify(rs(p), mid + 1, t, x, d);
pushUp(p);
}
int query(int p, int s, int t, int l, int r)
{
if (r < s || t < l)
return 0;
if (l <= s && t <= r)
return v(p);
int lft = query(ls(p), s, mid, l, r);
int rgh = query(rs(p), mid + 1, t, l, r);
int rsl;
// rsl = ...
return rsl;
}
};
- 动态开点线段树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) tr[p].ls
#define rs(p) tr[p].rs
#define mid ((s + t) >> 1)
struct Node
{
int ls, rs, v;
} tr[N << 5];
int tot;
void pushUp(int p)
{
if (ls(p))
// v(p) = ...
if (rs(p))
// v(p) = ...
}
void modify(int &p, int s, int t, int x, int d)
{
if (x < s || t < x)
return;
if (!p)
p = ++tot;
if (s == t)
{
// v(p) = ...
return;
}
modify(ls(p), s, mid, x, d);
modify(rs(p), mid + 1, t, x, d);
pushUp(p);
}
int query(int p, int s, int t, int l, int r)
{
if (r < s || t < l || !p)
return 0;
if (l <= s && t <= r)
return v(p);
int lft = query(ls(p), s, mid, l, r);
int rgh = query(rs(p), mid + 1, t, l, r);
int rsl;
// rsl = ...
return rsl;
}
};
- 主席树
struct SegmentTree
{
#define v(p) tr[p].v
#define ls(p) tr[p].ls
#define rs(p) tr[p].rs
#define mid ((s + t) >> 1)
struct Node
{
int ls, rs, v;
} tr[N << 5];
int tot;
void build(int &p, int s, int t)
{
p = ++tot;
if (s == t)
return;
build(ls(p), s, mid);
build(rs(p), mid + 1, t);
}
void pushUp(int p)
{
// v(p) = ...
}
void insert(int &p, int q, int s, int t, int x, int d)
{
if (x < s || t < x)
return;
p = ++tot, tr[p] = tr[q];
if (s == t)
{
// v(p) = ...
return;
}
insert(ls(p), ls(q), s, mid, x, d);
insert(rs(p), rs(q), mid + 1, t, x, d);
pushUp(p);
}
int query(int p, int s, int t, int l, int r)
{
if (r < s || t < l)
return 0;
if (l <= s && t <= r)
return v(p);
int lft = query(ls(p), s, mid, l, r);
int rgh = query(rs(p), mid + 1, t, l, r);
int rsl;
// rsl = ...
return rsl;
}
};
5.线段树分治
struct SegmentTree
{
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
#define mid ((s + t) >> 1)
vector<Node> tr[N << 2];
void modify(int p, int s, int t, int l, int r, Node d)
{
if (r < s || t < l)
return;
if (l <= s && t <= r)
{
tr[p].push_back(d);
return;
}
modify(ls(p), s, mid, l, r, d);
modify(rs(p), mid + 1, t, l, r, d);
}
} seg;
stack<int> his;
void undo(int tim)
{
while(his.size() > tim) {
// remove his.top() ...
his.pop();
}
}
void solve(int p, int s, int t)
{
int rec = his.size();
for (Node x : seg.tr[p])
{
// insert x ...
}
if (s == t)
{
// rsl = ...
undo(rec);
return;
}
undo(rec);
solve(ls(p), s, mid);
solve(rs(p), mid + 1, t);
}
6.CDQ分治
stack<int> rec;
void cdq(int s, int t)
{
if (s >= t)
return;
int mid = (s + t) >> 1;
cdq(s, mid);
sort(a + s, a + mid + 1, cmpB);
sort(a + mid + 1, a + t + 1, cmpB);
for (int i = mid + 1, j = s - 1; i <= t; ++i)
{
while (j < mid && a[j + 1].v < a[i].v) {
++j;
// insert a[j] ...
rec.push(a[j].p);
}
// rsl = ...
}
while (rec.size()) {
// remove rec.top() ...
rec.pop();
}
sort(a + mid + 1, a + t + 1, cmpA);
cdq(mid + 1, t);
}
7.整体二分
int qid[N], now;
vector<int> lft, rgh;
void solve(int s, int t, int l, int r)
{
if (s > t || l > r)
return;
if (s == t)
{
// rsl = ...
return;
}
int mid = (s + t) >> 1;
while (now < mid)
{
++now;
// insert now ...
}
while (now > mid)
{
// remove now ...
--now;
}
lft.clear(), rgh.clear();
for (int i = l; i <= r; ++i)
{
if (/* check... */)
lft.push_back(qid[i]);
else
rgh.push_back(qid[i]);
}
for (int i = 0; i < lft.size(); ++i)
qid[l + i] = lft[i];
for (int i = 0; i < rgh.size(); ++i)
qid[l + lft.size() + i] = rgh[i];
int siz = lft.size();
solve(s, mid, l, l + lft.size() - 1);
solve(mid + 1, t, l + siz, r);
}
8.*数列分块
#define lft(x) ((x - 1) * siz + 1)
#define rgh(x) min(lft(x + 1) - 1, n)
#define idx(x) ((x - 1) / siz + 1)
int siz, tot, val[M][M];
inline void init()
{
siz = sqrt(n), tot = (n + siz - 1) / siz;
for (int i = 1; i <= tot; ++i)
for (int j = i; j <= tot; ++j)
{
// val[i][j] = ...
}
}
inline int query(int l, int r)
{
int lft = idx(l), rgh = idx(r);
if (rgh - lft <= 1)
{
int rsl = 0;
for (int i = l; i <= r; ++i)
{
// rsl = ...
}
return rsl;
}
int rsl = val[lft + 1][rgh - 1];
for (int i = l; i <= rgh(lft); ++i)
{
// rsl = ...
}
for (int i = lft(rgh); i <= r; ++i)
{
// rsl = ...
}
return rsl;
}
9.*莫队
#define idx(x) ((x - 1) / siz + 1)
int siz;
struct Query
{
int l, r, id;
inline bool operator<(const Query &b) const
{
int b1 = idx(l), b2 = idx(b.l);
if (b1 != b2)
return b1 < b2;
return (b1 & 1) ? (r < b.r) : (r > b.r);
}
} q[M];
void add(int x)
{
// insert a[x] ...
}
void del(int x)
{
// delete a[x] ...
}
void solve()
{
siz = sqrt(n);
sort(q + 1, q + m + 1);
for (int i = 1, l = 1, r = 0; i <= m; ++i)
{
while (l > q[i].l)
add(--l);
while (r < q[i].r)
add(++r);
while (l < q[i].l)
del(l++);
while (r > q[i].r)
del(r--);
// rsl[q[i].id] = ...
}
}
图论
1.倍增LCA
vector<int> g[N];
int dep[N], par[N][T + 1];
void dfs(int u, int fa)
{
dep[u] = dep[fa] + 1, par[u][0] = fa;
for (int i = 1; i <= T; ++i)
par[u][i] = par[par[u][i - 1]][i - 1];
for (int v : g[u])
if (v != fa)
dfs(v, u);
}
int getLca(int u, int v)
{
if (dep[u] > dep[v])
swap(u, v);
for (int i = T; i >= 0; --i)
if (dep[par[v][i]] >= dep[u])
v = par[v][i];
if (u == v)
return u;
for (int i = T; i >= 0; --i)
if (par[u][i] != par[v][i])
u = par[u][i], v = par[v][i];
return par[u][0];
}
2.最短路
- Dijkstra
vector<pair<int, int>> g[N];
int dis[N];
void dijkstra(int s)
{
priority_queue<pair<int, int>> q;
vector<bool> vis(n + 5);
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
q.push({0, s});
while (q.size())
{
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto [v, w] : g[u])
{
if (dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
q.push({-dis[v], v});
}
}
}
}
- Floyd
int g[N][N];
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]);
}
3.树的重心
-
树以重心为根时,任一子树大小不超过原树大小的一半.
-
树的重心如果不唯一,则恰有两个,这两个重心相邻.
-
树上添/删一个叶子,重心最多只移动一条边.
-
两棵树通过一条边相连,那么新树的重心在连接原来两棵树的重心的路径上.
-
树上所有的点到树的重心的距离之和最短.
int siz[N], f[N], root;
void dfs(int u, int fa)
{
siz[u] = 1, f[u] = 0;
for (int v : g[u])
{
if (v == fa)
continue;
dfs(v, u);
siz[u] += siz[v];
f[u] = max(f[u], siz[v]);
}
f[u] = max(f[u], n - siz[u]);
if (f[u] <= (n >> 1))
root = u;
}
4.最小生成树
- Kruskal
int Kruskal()
{
int rsl = 0;
sort(edg + 1, edg + m + 1, [](Edge &a, Edge &b)
{ return a.w < b.w; });
for (int i = 1; i <= m; ++i)
{
auto [u, v, w] = edg[i];
u = dsu.find(u), v = dsu.find(v);
if(u == v) continue;
dsu.fa[u] = v, rsl += w;
}
return rsl;
}
- Prim
int Prim()
{
int rsl = 0;
vector<int> d(n + 5, 1e9);
vector<bool> vis(n + 5);
d[1] = 0;
for (int i = 1; i <= n; ++i)
{
int u = 0;
for (int v = 1; v <= n; ++v)
if (!vis[v] && d[v] < d[u])
u = v;
rsl += d[u], vis[u] = 1;
for (int v = 1; v <= n; ++v)
if (!vis[v])
d[v] = min(d[v], g[u][v]);
}
return rsl;
}
5.Tarjan
- 强连通分量
vector<int> g[N];
int dfn[N], tim, low[N], scc[N], siz[N], tot;
bool ins[N];
stack<int> stc;
void tarjan(int u)
{
dfn[u] = low[u] = ++tim;
stc.push(u), ins[u] = 1;
for (int v : g[u])
{
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (ins[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u])
{
++tot;
while (1)
{
int v = stc.top();
stc.pop();
ins[v] = 0, scc[v] = tot;
if (v <= n)
++siz[tot];
if (v == u)
break;
}
}
}
- 割辺
struct edg
{
int v, nex;
} edg[M];
int head[N], tot = 1;
int dfn[N], low[N], tim, dcc[N], cnt;
bool cut[N];
void tarjan(int u, int in)
{
dfn[u] = low[u] = ++tim;
for (int i = head[u]; i; i = edg[i].nex)
{
int v = edg[i].v;
if (!dfn[v])
{
tarjan(v, i);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u])
cut[i] = cut[i ^ 1] = 1;
}
else if (i != (in ^ 1))
low[u] = min(low[u], dfn[v]);
}
}
- 割点/圆方树
vector<int> g[N], dcc[N];
int dfn[N], low[N], tim, root, tot;
bool cut[N];
stack<int> stc;
void tarjan(int u)
{
dfn[u] = low[u] = ++tim;
if (u == root && !g[u].size())
{
dcc[++tot].push_back(u);
return;
}
int flag = 1;
stc.push(u);
for (int v : g[u])
{
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u])
{
++flag;
if (u != root || flag > 1)
cut[u] = 1;
++tot;
while (1)
{
int w = stc.top();
stc.pop();
dcc[tot].push_back(w);
if (w == v)
break;
}
stc.push(u);
}
}
else
low[u] = min(low[u], dfn[v]);
}
}
6.欧拉路
-
有向图欧拉路径:图中恰好存在 \(1\) 点出度 = 入度 + \(1\)(即 \(S\) ).
-
有向图欧拉回路:所有点的入度 = 出度( \(S\) 和 \(T\) 任意).
-
无向图欧拉路径:图中恰好存在 \(2\) 点的度数是奇数,即 \(S\) 和 \(T\).
-
无向图欧拉回路:所有点的度数都是偶数( \(S\) 和 \(T\) 任意).
- 有向图欧拉路径
multiset<int> g[N];
stack<int> path;
void dfs(int u)
{
while (g[u].size())
{
auto p = g[u].begin();
g[u].erase(p);
dfs(*p);
}
path.push(u);
}
void printPath()
{
while (path.size())
{
cout << path.top() << ' ';
path.pop();
}
cout << '\n';
}
- 无向图
有向图基础上增加判断来边即可(注意重边).
7.树上启发式合并
vector<int> g[N];
int siz[N], son[N], rsl[N];
void pre(int u)
{
siz[u] = 1;
for (int v : g[u])
{
pre(v), siz[u] += siz[v];
son[u] = siz[v] > siz[son[u]] ? v : son[u];
}
}
void add(int u, int d)
{
// insert/remove u ...
for (int v : g[u])
add(v, d);
}
void dfs(int u, bool type)
{
for (int v : g[u])
if (v != son[u])
dfs(v, 0);
if (son[u])
dfs(son[u], 1);
for (int v : g[u])
if (v != son[u])
add(v, 1);
// insert u ...
// calculate u's result ...
if (!type)
add(u, -1);
}
8.*重链剖分
vector<int> g[N];
int dep[N], par[N], siz[N], son[N];
int dfn[N], top[N], tim;
void dfs1(int u, int fa)
{
dep[u] = dep[fa] + 1, par[u] = fa, siz[u] = 1;
for (int v : g[u])
{
if (v == fa)
continue;
dfs1(v, u);
siz[u] += siz[v];
if (siz[v] > siz[son[u]])
son[u] = v;
}
}
void dfs2(int u, int t)
{
dfn[u] = ++tim, top[u] = t;
if (!son[u])
return;
dfs2(son[u], t);
for (int v : g[u])
if (v != par[u] && v != son[u])
dfs2(v, v);
}
int query(int u, int v)
{
int rsl = 0;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
swap(u, v);
// rsl = ...
u = par[top[u]];
}
if (dep[u] < dep[v])
swap(u, v);
// rsl = ...
return rsl;
}
9.*点分治
bool vis[N];
int tot, siz[N], root;
void getRoot(int u, int fa)
{
siz[u] = 1;
int f = 0;
for (auto [v, w] : g[u])
{
if (vis[v] || v == fa)
continue;
getRoot(v, u);
siz[u] += siz[v], f = max(f, siz[v]);
}
f = max(f, tot - siz[u]);
if (f <= (tot >> 1))
root = u;
}
int dis[N];
unordered_map<int, int> cnt;
void modify(int u, int fa, int d)
{
cnt[dis[u]] += d;
for (auto [v, w] : g[u])
if (!vis[v] && v != fa)
modify(v, u, d);
}
void query(int u, int fa)
{
// rsl = ...
for (auto [v, w] : g[u])
if (!vis[v] && v != fa)
dis[v] = dis[u] + w, query(v, u);
}
void calc(int u)
{
dis[u] = 0;
for (auto [v, w] : g[u])
{
if (vis[v])
continue;
dis[v] = w;
query(v, u);
modify(v, u, 1);
}
modify(u, 0, -1);
}
void solve(int u)
{
vis[u] = 1;
calc(u);
int rec = tot;
for (auto [v, w] : g[u])
{
if (vis[v])
continue;
tot = siz[v] < siz[u] ? siz[v] : rec - siz[u];
getRoot(v, u);
solve(root);
}
}
数学
1.exgcd
int exgcd(int a, int b, int &x, int &y)
{
if (!b)
{
x = 1, y = 0;
return b;
}
int d = exgcd(b, a % b, x, y);
int t = x, x = y, y = t - a / b * y;
return d;
}
2.逆元
- exgcd求逆元
int inv(int n)
{
int x, y;
exgcd(n, P, x, y);
return (x % P + P) % P;
}
- 线性预处理逆元
int inv[N];
void init()
{
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = inv[P % i] * (P - P / i) % P;
}
3.线性筛
vector<int> pri;
void getPri(int n)
{
vector<bool> vis(n + 5);
for (int i = 2; i <= n; ++i)
{
if (!vis[i])
pri.push_back(i);
for (int p : pri)
{
if (p > n / i)
break;
vis[p * i] = 1;
if (i % p == 0)
break;
}
}
}
4.Lucas定理
int lucas(int n, int m)
{
return m ? lucas(n / P, m / P) * C(n % P, m % P) % P : 1;
}
5.同余最短路
for (int i = 0; i < mn; ++i)
for (int j = 2; j <= n; ++j)
g[i].push_back({(i + a[j]) % mn, a[j]});
dijkstra(0);
int rsl = 0;
for (int i = 0; i < mn; ++i)
{
if (dis[i] <= r)
rsl += (r - dis[i]) / mn + 1;
if (dis[i] <= l - 1)
rsl -= (l - 1 - dis[i]) / mn + 1;
}
6.矩阵
\[c_{i,j}=\sum\limits_{k=1}^m{a_{i,k} \times b_{k,j}}
\]
- 矩阵乘法
struct Matrix
{
int n, m;
vector<vector<int>> a;
Matrix(int _n, int _m)
{
n = _n, m = _m;
a.resize(n + 1);
for (int i = 1; i <= n; ++i)
a[i].resize(m + 1);
};
Matrix operator*(const Matrix &b)
{
assert(m == b.n);
Matrix c(n, b.m);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= b.m; ++j)
for (int k = 1; k <= m; ++k)
(c.a[i][j] += a[i][k] * b.a[k][j] % P) %= P;
return c;
}
};
- 矩阵快速幂
Matrix power(Matrix n, int m)
{
assert(n.n == n.m);
Matrix rsl(n.n, n.n);
for (int i = 1; i <= n.n; ++i)
rsl.a[i][i] = 1;
for (; m; m >>= 1, n = n * n)
if (m & 1)
rsl = rsl * n;
return rsl;
}
7.高斯消元
long double a[N], b[N], c[N][N];
void guass()
{
for (int i = 1; i <= n; ++i)
{
for (int j = i; j <= n; ++j)
{
if (abs(c[j][i] <= 1e-8))
continue;
swap(c[i], c[j]), swap(b[i], b[j]);
break;
}
for (int j = 1; j <= n; ++j)
{
if (i == j)
continue;
ldb rate = c[j][i] / c[i][i];
for (int k = i; k <= n; ++k)
c[j][k] -= c[i][k] * rate;
b[j] -= b[i] * rate;
}
}
for (int i = 1; i <= n; ++i)
a[i] = b[i] / c[i][i];
}
8.*异或线性基
int base[N];
bool insert(int x)
{
for (int i = T; i >= 0; --i)
{
if (!((x >> i) & 1))
continue;
if (!base[i])
{
base[i] = x;
return 1;
}
x ^= base[i];
}
return 0;
}
字符串
1.哈希
- 一维哈希
#define ull unsigned long long
#define B 45141
int pwe[N], a[N], s[N];
void init()
{
for (int i = 1; i <= n; ++i)
pwe[i] = pwe[i - 1] * B;
for (int i = 1; i <= n; ++i)
s[i] = s[i - 1] * B + a[i];
}
ull query(int l, int r)
{
return s[r] - s[l - 1] * pwe[r - l + 1];
}
- 二维哈希
#define ull unsigned long long
#define B1 1451
#define B2 45141
ull pwe[0][N], a[N][N], s[N][N];
void init()
{
pwe[0][0] = pwe[1][0] = 1;
for (int i = 1; i <= max(n, m); ++i)
{
pwe[0][i] = pwe[0][i - 1] * B1;
pwe[1][i] = pwe[1][i - 1] * B2;
}
for (int i = 1; i <= n; ++i)
{
ull val = 0;
for (int j = 1; j <= m; ++j)
{
val = val * B1 + (ull)a[i][j];
s[i][j] = val + s[i - 1][j] * B2;
}
}
}
ull get(int x1, int y1, int x2, int y2)
{
int a = x2 - x1 + 1, b = y2 - y1 + 1;
return s[x2][y2] -
s[x1 - 1][y2] * pwe[1][a] -
s[x2][y1 - 1] * pwe[0][b] +
s[x1 - 1][y1 - 1] * pwe[1][a] * pwe[0][b];
}
2.KMP
string s, t;
int n, m, nex[N], f[N];
for (int i = 2, j = 0; i <= m; ++i)
{
while (j && t[j + 1] != t[i])
j = nex[j];
if (t[j + 1] == t[i])
++j;
nex[i] = j;
}
for (int i = 1, j = 0; i <= n; ++i)
{
while (j && (j == m || t[j + 1] != s[i]))
j = nex[j];
if (t[j + 1] == s[i])
++j;
f[i] = j;
}
3.Manacher
int manacher(string &str)
{
vector<int> f(n + 5);
int ans = 0;
vector<char> s;
s.push_back(' ');
s.push_back(' ');
for (int i = 0; i < (int)str.size(); ++i)
{
s.push_back(str[i]);
s.push_back(' ');
}
for (int i = 1, mid = 0, r = 0; i < (int)s.size(); ++i)
{
if (i <= r)
f[i] = min(f[(mid << 1) - i], r - i + 1);
while (s[i - f[i]] == s[i + f[i]])
++f[i];
if (i + f[i] > r)
r = i + f[i] - 1, mid = i;
ans = max(ans, f[i]);
}
return ans - 1;
}
4.最小表示法
string s;
int i = 1, j = 2;
for (int k = 0; i <= n && j <= n && k < n;)
{
char a = s[(i + k) % n + 1];
char b = s[(j + k) % n + 1];
if (a == b)
++k;
else
{
if (a > b)
i += k + 1;
else
j += k + 1;
if (i == j)
++i;
k = 0;
}
}
i = min(i, j);
5.字典树
struct Trie
{
int tr[M][26], val[M], tot = 1;
void insert(string &s)
{
int p = 1;
for (int i = 0; i < s.size(); ++i)
{
++val[p];
int w = s[i] - 'a';
if (!tr[p][w])
tr[p][w] = ++tot;
p = tr[p][w];
}
++val[p];
}
};
杂项
1.单调队列/栈
- 单调队列
deque<int> q;
for (int i = 1; i <= n; i++)
{
while (!q.empty() && a[i] < a[q.back()])
q.pop_back();
q.push_back(i);
if (i - q.front() >= k)
q.pop_front();
if (i >= k)
f[i] = q.front();
}
- 单调栈
stack<int> stc;
for (int i = 1; i <= n; ++i)
{
while (stc.size() && a[stc.top()] < a[i])
f[stc.top()] = i, stc.pop();
stc.push(i);
}
2.反悔贪心
prioirty_queue<int> q;
for (int i = 1, t = 0; i <= n; ++i)
{
if (t + a[i].w <= a[i].l)
{
t += a[i].w;
q.push(a[i].w);
}
else if (q.size() && q.top() > a[i].w)
{
t -= q.top();
q.pop(), q.push(a[i].w);
t += a[i].w;
}
}
3.单调队列优化多重背包
int n, m, v[N], w[N], k[N], f[2][M];
int g(int i, int y, int x)
{
return f[i & 1 ^ 1][x * w[i] + y] - x * v[i];
}
for (int i = 1; i <= n; ++i)
for (int y = 0; y < w[i]; ++y)
{
deque<int> q;
for (int x = 0; x * w[i] + y <= m; ++x)
{
while (q.size() && x - q.front() > k[i])
q.pop_front();
while (q.size() && g(i, y, q.back()) <= g(i, y, x))
q.pop_back();
q.push_back(x);
f[i & 1][x * w[i] + y] = v[i] * x + g(i, y, q.front());
}
}
4.*模拟退火
-
求最大值:\(P(\delta)=e^{\frac{\delta}{t}}\)
-
求最小值:\(P(\delta)=e^{-\frac{\delta}{t}}\)
#define dbl double
dbl ans;
dbl getRand()
{
return rand() % 100000 / 100000.0;
}
dbl getAns()
{
dbl tmp;
// calculate the temp answer...
ans = max(ans, tmp);
return tmp;
}
void SA(dbl beg, dbl end, dbl dec, int cnt)
{
dbl t = beg, now = ans;
while (t > end)
{
int x = rand() % n + 1, y = rand() % n + 1;
if (x == y)
continue;
swap(a[x], a[y]);
dbl tmp = getAns();
if (tmp < now || exp(-(tmp - now) / t) > getRand())
now = tmp;
else
swap(a[x], a[y]);
t *= dec;
}
for (int i = 1; i <= cnt; ++i)
{
int x = rand() % n + 1, y = rand() % n + 1;
if (x == y)
continue;
swap(a[x], a[y]);
getAns();
swap(a[x], a[y]);
}
}

浙公网安备 33010602011771号