观前须知
Sugar_Cube的博客园主页
声明
本文使用 CC BY-NC-SA 4.0 许可。
本文包含了笔者常用的 OI 算法、数据结构的模板。
不保证算法最优,但能通过相应的模板题(如果有会挂出)。
如有错误请在评论区指出(虽然大抵没人看就是了)。
码风是笔者的个人习惯(能看懂就好喵)。
代码会省略快读 Read()。
持续更新。咕咕咕
输入输出优化
快读
inline int Read() {
int res = 0;
bool flag = false;
int c = getchar();
//~c防止EOF读到-1而卡死循环,一般情况可省略
while ((c < '0' || c > '9') && ~c) {
flag |= c == '-';
c = getchar();
}
while (c >= '0' && c <= '9') {
res = (res << 1) + (res << 3) + (c ^ 48);
c = getchar();
}
return flag ? -res : res;
}
浮点数快读
typedef long double ld;
inline ld Read() {
ld res = 0;
bool flag = false;
int c = getchar();
while ((c < '0' || c > '9') && ~c) {
flag |= c == '-';
c = getchar();
}
while (c >= '0' && c <= '9') {
res = res * 10 + (c ^ 48);
c = getchar();
}
if (c == '.') {
c = getchar();
ld f = 1;
while (c >= '0' && c <= '9') {
f /= 10;
res += f * (c ^ 48);
c = getchar();
}
}
return flag ? -res : res;
}
数据结构
树状数组
Luogu P3374 【模板】树状数组 1
constexpr int AwA = 5e5 + 10;
int n, m;
int a[AwA];
int c[AwA];
inline void Update(int idx, int x) {
while (idx <= n) {
c[idx] += x;
idx += idx & -idx;
}
}
inline int Query(int idx) {
int res = 0;
while (idx) {
res += c[idx];
idx -= idx & -idx;
}
return res;
}
int main() {
n = Read(), m = Read();
//根据树状数组定义O(n)建树
for (int i = 1; i <= n; i++) a[i] = a[i - 1] + Read();
for (int i = 1; i <= n; i++) c[i] = a[i] - a[i - (i & -i)];
while (m--) {
int op = Read(), x = Read(), y = Read();
if (op == 1) Update(x, y);
else printf("%d\n", Query(y) - Query(x - 1));
}
return 0;
}
ST表
Luogu P3865 【模板】ST表
constexpr int AwA = 1e5 + 10;
constexpr int QwQ = 21;
int n, m;
int f[AwA][QwQ], a[AwA];
inline void PreST() {
for (int i = 1; i <= n; i++) f[i][0] = a[i];
for (int j = 1; j <= __lg(n); j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
inline int Query(int l, int r) {
int k = __lg(r - l + 1);
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
n = Read(), m = Read();
for (int i = 1; i <= n; i++) a[i] = Read();
PreST();
while (m--) {
int l = Read(), r = Read();
printf("%d\n", Query(l, r));
}
return 0;
}
线段树
Luogu P3373 【模板】线段树2
#include<bits/stdc++.h>
using namespace std;
inline static int Read() {
int res = 0;
bool flag = false;
int c = getchar();
while ((c < '0' || c > '9') && ~c) {
flag |= c == '-';
c = getchar();
}
while (c >= '0' && c <= '9') {
res = (res << 1) + (res << 3) + (c ^ 48);
c = getchar();
}
return flag ? -res : res;
}
static constexpr int AwA = 1e5 + 10;
int n, Mod, Q;
int a[AwA];
//不动态开点的线段树要开4倍数组
struct Node {
int mul_tag, add_tag;
int sum;
} tr[AwA << 2];
inline void PushUp(int u) {
//线段树的左右儿子分别为2*u,2*u+1
tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % Mod;
}
//本棵线段树最重要的一个函数
inline void PushDown(int u, int l, int r) {
int lc = u << 1, rc = u << 1 | 1, mid = (l + r) >> 1;
if (tr[u].mul_tag != 1) {
tr[lc].mul_tag = int(1ll * tr[lc].mul_tag * tr[u].mul_tag % Mod);
tr[lc].add_tag = int(1ll * tr[lc].add_tag * tr[u].mul_tag % Mod);
tr[lc].sum = int(1ll * tr[lc].sum * tr[u].mul_tag % Mod);
tr[rc].mul_tag = int(1ll * tr[rc].mul_tag * tr[u].mul_tag % Mod);
tr[rc].add_tag = int(1ll * tr[rc].add_tag * tr[u].mul_tag % Mod);
tr[rc].sum = int(1ll * tr[rc].sum * tr[u].mul_tag % Mod);
tr[u].mul_tag = 1;
}
if (tr[u].add_tag) {
tr[lc].add_tag = (tr[lc].add_tag + tr[u].add_tag) % Mod;
tr[lc].sum = int((tr[lc].sum + 1ll * tr[u].add_tag * (mid - l + 1)) % Mod);
tr[rc].add_tag = (tr[rc].add_tag + tr[u].add_tag) % Mod;
tr[rc].sum = int((tr[rc].sum + 1ll * tr[u].add_tag * (r - mid)) % Mod);
tr[u].add_tag = 0;
}
}
//O(n)建树
void Build(int u, int l, int r) {
tr[u] = {1, 0, 0};
if (l == r) return void(tr[u].sum = a[l]);
int mid = (l + r) >> 1;
Build(u << 1, l, mid);
Build(u << 1 | 1, mid + 1, r);
PushUp(u);
}
void UpdateMul(int u, int l, int r, int lx, int rx, int val) {
if (lx <= l && r <= rx) {
tr[u].sum = int(1ll * tr[u].sum * val % Mod);
tr[u].mul_tag = int(1ll * tr[u].mul_tag * val % Mod);
tr[u].add_tag = int(1ll * tr[u].add_tag * val % Mod);
return;
}
PushDown(u, l, r);
int mid = (l + r) >> 1;
if (lx <= mid) UpdateMul(u << 1, l, mid, lx, rx, val);
if (mid + 1 <= rx) UpdateMul(u << 1 | 1, mid + 1, r, lx, rx, val);
PushUp(u);
}
void UpdateAdd(int u, int l, int r, int lx, int rx, int val) {
if (lx <= l && r <= rx) {
tr[u].sum = int((1ll * val * (r - l + 1) + tr[u].sum) % Mod);
tr[u].add_tag = (tr[u].add_tag + val) % Mod;
return;
}
PushDown(u, l, r);
int mid = (l + r) >> 1;
if (lx <= mid) UpdateAdd(u << 1, l, mid, lx, rx, val);
if (mid + 1 <= rx) UpdateAdd(u << 1 | 1, mid + 1, r, lx, rx, val);
PushUp(u);
}
int Query(int u, int l, int r, int lx, int rx) {
if (lx <= l && r <= rx) return tr[u].sum;
PushDown(u, l, r);
int mid = (l + r) >> 1, res = 0;
if (lx <= mid) res = (res + Query(u << 1, l, mid, lx, rx)) % Mod;
if (mid + 1 <= rx) res = (res + Query(u << 1 | 1, mid + 1, r, lx, rx)) % Mod;
return res;
}
int main() {
n = Read(), Q = Read(), Mod = Read();
for (int i = 1; i <= n; i++) a[i] = Read();
Build(1, 1, n);
while (Q--) {
int op = Read();
if (op == 1) {
int l = Read(), r = Read(), val = Read();
UpdateMul(1, 1, n, l, r, val % Mod);
} else if (op == 2) {
int l = Read(), r = Read(), val = Read();
UpdateAdd(1, 1, n, l, r, val % Mod);
} else {
int l = Read(), r = Read();
printf("%d\n", Query(1, 1, n, l, r));
}
}
return 0;
}
FHQ Treap
Luogu P3369 普通平衡树
constexpr int AwA = 1e6 + 10;
//生成随机数
mt19937 rd{random_device()()};
struct Node {
int lc, rc, sz;
int val;
//mt19937 返回uint类型
unsigned int rd;
} tr[AwA];
int rt, tot;
inline int NewNode(int _val) {
tr[++tot] = {0, 0, 1, _val, rd()};
return tot;
}
inline void PushUp(int u) {
tr[u].sz = tr[tr[u].lc].sz + tr[tr[u].rc].sz + 1;
}
void SplitVal(int u, int val, int &x, int &y) {
//压行.jpg
if (!u) return void(x = y = 0);
if (tr[u].val <= val) {
x = u;
SplitVal(tr[u].rc, val, tr[x].rc, y);
} else {
y = u;
SplitVal(tr[u].lc, val, x, tr[y].lc);
}
PushUp(u);
}
int Merge(int x, int y) {
if (!x || !y) return x | y;
if (tr[x].rd <= tr[y].rd) {
tr[x].rc = Merge(tr[x].rc, y);
PushUp(x);
return x;
}
tr[y].lc = Merge(x, tr[y].lc);
PushUp(y);
return y;
}
inline void Insert(int _val) {
int x, y;
SplitVal(rt, _val, x, y);
rt = Merge(Merge(x, NewNode(_val)), y);
}
int main() {
int Q = Read();
while (Q--) {
int op = Read(), v = Read();
if (op == 1) Insert(v);
else if (op == 2) {
int x, y, z;
SplitVal(rt, v, x, z);
SplitVal(x, v - 1, x, y);
y = Merge(tr[y].lc, tr[y].rc);
rt = Merge(Merge(x, y), z);
} else if (op == 3) {
int x, y;
SplitVal(rt, v - 1, x, y);
printf("%d\n", tr[x].sz + 1);
rt = Merge(x, y);
} else if (op == 4) {
int u = rt;
while (true) {
int sz = tr[tr[u].lc].sz + 1;
if (sz == v) break;
else if (sz > v) u = tr[u].lc;
else u = tr[u].rc, v -= sz;
}
printf("%d\n", tr[u].val);
} else if (op == 5) {
int x, y;
SplitVal(rt, v - 1, x, y);
int u = x;
while (tr[u].rc) u = tr[u].rc;
rt = Merge(x, y);
printf("%d\n", tr[u].val);
} else {
int x, y;
SplitVal(rt, v, x, y);
int u = y;
while (tr[u].lc) u = tr[u].lc;
rt = Merge(x, y);
printf("%d\n", tr[u].val);
}
}
return 0;
}
FHQ Treap 文艺平衡树
Luogu P3391 文艺平衡树
constexpr int AwA = 1e5 + 10;
mt19937 rd{random_device()()};
struct Node {
int lc, rc, sz;
int val;
unsigned int rd;
bool revTag;
} tr[AwA];
int rt, tot;
inline int NewNode(int _val) {
tr[++tot] = {0, 0, 1, _val, rd(), false};
return tot;
}
inline void PushUp(int u) {
tr[u].sz = tr[tr[u].lc].sz + tr[tr[u].rc].sz + 1;
}
inline void PushDown(int u) {
if (!tr[u].revTag) return;
swap(tr[u].lc, tr[u].rc);
if (tr[u].lc) tr[tr[u].lc].revTag ^= 1;
if (tr[u].rc) tr[tr[u].rc].revTag ^= 1;
tr[u].revTag = false;
}
void SplitSz(int u, int sz, int &x, int &y) {
if (!u) return void(x = y = 0);
PushDown(u);
if (tr[tr[u].lc].sz + 1 <= sz) {
x = u;
SplitSz(tr[u].rc, sz - tr[tr[u].lc].sz - 1, tr[x].rc, y);
} else {
y = u;
SplitSz(tr[u].lc, sz, x, tr[y].lc);
}
PushUp(u);
}
int Merge(int x, int y) {
if (!x || !y) return x | y;
if (tr[x].rd <= tr[y].rd) {
PushDown(x);
tr[x].rc = Merge(tr[x].rc, y);
PushUp(x);
return x;
}
PushDown(y);
tr[y].lc = Merge(x, tr[y].lc);
PushUp(y);
return y;
}
inline void Build(int n) {
for (int i = 1; i <= n; i++) NewNode(i);
static int stk[AwA], top;
stk[top = 1] = 1;
for (int i = 2; i <= n; i++) {
int tmp = 0;
while (top && tr[stk[top]].rd > tr[i].rd) PushUp(tmp = stk[top--]);
if (top) tr[stk[top]].rc = i;
if (tmp) tr[i].lc = tmp;
stk[++top] = i;
}
for (int i = top; i; i--) PushUp(i);
rt = stk[1];
}
void Print(int u) {
if (!u) return;
PushDown(u);
Print(tr[u].lc);
printf("%d ", tr[u].val);
Print(tr[u].rc);
}
int main() {
int n = Read(), Q = Read();
Build(n);
while (Q--) {
int l = Read(), r = Read();
int x, y, z;
SplitSz(rt, r, x, z);
SplitSz(x, l - 1, x, y);
tr[y].revTag ^= 1;
rt = Merge(Merge(x, y), z);
}
Print(rt);
putchar('\n');
return 0;
}
块状链表
因为笔者暂时没有POJ账号所以模板题先咕咕咕喵
static constexpr int QwQ = 1e3;
struct Node {
int nxt, sz;
int a[(QwQ << 1) + 10];
inline void Insert(int pos, int val) {
for (int i = sz; i >= pos; i--) a[i + 1] = a[i];
a[pos] = val;
sz++;
}
inline void Delete(int pos) {
for (int i = pos; i < sz; i++) a[i] = a[i + 1];
sz--;
}
} t[QwQ + 10];
int tcnt = 1;
inline void Check(int u) {
if (t[u].sz < QwQ << 1) return;
int v = ++tcnt;
t[v].nxt = t[u].nxt;
t[u].nxt = v;
t[v].sz = t[u].sz - QwQ;
for (int i = 1; i <= t[v].sz; i++) t[v].a[i] = t[u].a[i + QwQ];
t[u].sz = QwQ;
}
inline void Insert(int pos, int val) {
int u;
for (u = 1; t[u].nxt && t[u].sz < pos; pos -= t[u].sz, u = t[u].nxt);
t[u].Insert(min(pos, t[u].sz + 1), val);
Check(u);
}
inline int Query(int pos) {
int u;
for (u = 1; t[u].nxt && t[u].sz < pos; pos -= t[u].sz, u = t[u].nxt);
return t[u].a[pos];
}
inline void Delete(int pos) {
int u;
for (u = 1; t[u].nxt && t[u].sz < pos; pos -= t[u].sz, u = t[u].nxt);
t[u].Delete(pos);
}
图论
Dijkstra
P4779 【模板】单源最短路径(标准版)
constexpr int AwA = 1e5 + 10;
constexpr int QwQ = 2e5 + 10;
struct Edge {
int nxt, v, w;
} e[QwQ];
int head[AwA], ecnt;
inline void AddEdge(int w, int v, int u) {
e[++ecnt] = {head[u], v, w};
head[u] = ecnt;
}
int n, m, S;
int dis[AwA];
bool vis[AwA];
inline void Dijkstra() {
priority_queue<pair<int, int>> q;
memset(dis + 1, 0x3f, sizeof(int) * n);
memset(vis + 1, 0, sizeof(bool) * n);
dis[S] = 0;
q.emplace(0, S);
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (dis[u] + e[i].w < dis[v]) {
dis[v] = dis[u] + e[i].w;
q.emplace(-dis[v], v);
}
}
}
}
int main() {
n = Read(), m = Read(), S = Read();
for (int i = 1; i <= m; i++) AddEdge(Read(), Read(), Read());
Dijkstra();
for (int i = 1; i <= n; i++) printf("%d ", dis[i]);
putchar('\n');
return 0;
}
Kruskal
P3366 【模板】最小生成树
constexpr int AwA = 5e3 + 10;
constexpr int QwQ = 2e5 + 10;
struct {
int u, v, w;
} e[QwQ];
int n, m;
int fa[AwA];
int Find(int x) { return fa[x] ? fa[x] = Find(fa[x]) : x; }
inline int Kruskal() {
sort(e + 1, e + m + 1, [](auto &e1, auto &e2) { return e1.w < e2.w; });
int cnt = 0, ans = 0;
for (int i = 1; i <= m && cnt < n - 1; i++) {
int x = Find(e[i].u), y = Find(e[i].v);
if (x == y) continue;
fa[x] = y;
ans += e[i].w;
cnt++;
}
return cnt == n - 1 ? ans : -1;
}
int main() {
n = Read(), m = Read();
for (int i = 1; i <= m; i++) e[i] = {Read(), Read(), Read()};
int res = Kruskal();
~res ? printf("%d\n", res) : puts("orz");
return 0;
}
树上问题
倍增LCA
Luogu P3379 【模板】最近公共祖先(LCA)
constexpr int AwA = 5e5 + 10;
constexpr int QwQ = 21;
struct Edge {
int nxt, v;
} e[AwA << 1];
int head[AwA], ecnt;
inline void AddEdge(int u, int v) {
e[++ecnt] = {head[u], v};
head[u] = ecnt;
}
int n, m, rt;
int fa[AwA][QwQ], dep[AwA];
void Dfs(int u, int _fa) {
fa[u][0] = _fa;
dep[u] = dep[fa[u][0]] + 1;
for (int j = 0; j < __lg(dep[u]); fa[u][j + 1] = fa[fa[u][j]][j], j++);
for (int i = head[u]; i; i = e[i].nxt) if (e[i].v != fa[u][0]) Dfs(e[i].v, u);
}
inline int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = __lg(dep[x] - dep[y]); ~i; i--)
if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if (x == y) return x;
for (int i = __lg(dep[x]); ~i; i--)
if (fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main() {
n = Read(), m = Read(), rt = Read();
for (int i = 1; i < n; i++) {
int u = Read(), v = Read();
AddEdge(u, v);
AddEdge(v, u);
}
Dfs(rt, 0);
while (m--) printf("%d\n", LCA(Read(), Read()));
return 0;
}
欧拉序lca
Luogu P3379 【模板】最近公共祖先(LCA)
constexpr int AwA = 5e5 + 10;
constexpr int QwQ = 22;
struct Edge {
int nxt, v;
} e[AwA << 1];
int head[AwA], ecnt;
inline void AddEdge(int u, int v) {
e[++ecnt] = {head[u], v};
head[u] = ecnt;
}
int n, m, rt;
int dep[AwA], dfn[AwA], idfn[AwA << 1];
int f[AwA << 1][QwQ], g[AwA << 1][QwQ];
void Dfs(int u, int fa = 0) {
dep[u] = dep[fa] + 1;
idfn[++idfn[0]] = u;
dfn[u] = idfn[0];
for (int i = head[u]; i; i = e[i].nxt)
if (e[i].v != fa) Dfs(e[i].v, u), idfn[++idfn[0]] = u;
}
inline void InitST() {
for (int i = 1; i <= idfn[0]; i++) f[i][0] = dep[idfn[i]], g[i][0] = idfn[i];
for (int j = 1; j <= __lg(idfn[0]); j++)
for (int i = 1; i + (1 << j) - 1 <= idfn[0]; i++) {
f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
if (f[i][j - 1] < f[i + (1 << (j - 1))][j - 1]) g[i][j] = g[i][j - 1];
else g[i][j] = g[i + (1 << (j - 1))][j - 1];
}
}
inline int QueryMnPos(int l, int r) {
int k = __lg(r - l + 1);
if (f[l][k] < f[r - (1 << k) + 1][k]) return g[l][k];
return g[r - (1 << k) + 1][k];
}
inline int LCA(int x, int y) {
int l = dfn[x], r = dfn[y];
if (l > r) swap(l, r);
return QueryMnPos(l, r);
}
int main() {
n = Read(), m = Read(), rt = Read();
for (int i = 1; i < n; i++) {
int u = Read(), v = Read();
AddEdge(u, v);
AddEdge(v, u);
}
Dfs(rt);
InitST();
while (m--) printf("%d\n", LCA(Read(), Read()));
return 0;
}
树链剖分
P3384 【模板】重链剖分/树链剖分
typedef long long ll;
constexpr int AwA = 1e5 + 10;
struct Edge {
int nxt, v;
} e[AwA << 1];
int head[AwA], ecnt;
inline void AddEdge(int u, int v) {
e[++ecnt] = {head[u], v};
head[u] = ecnt;
e[++ecnt] = {head[v], u};
head[v] = ecnt;
}
int n, m, rt, Mod;
ll sum[AwA << 2], tag[AwA << 2];
int sz[AwA], son[AwA], fa[AwA], top[AwA], dfn[AwA], dep[AwA];
int a[AwA];
void Update(int u, int l, int r, int lx, int rx, int val) {
if (l == lx && r == rx) {
tag[u] += val;
tag[u] %= Mod;
return;
}
sum[u] += 1ll * val * (rx - lx + 1);
sum[u] %= Mod;
int mid = (l + r) >> 1;
if (lx <= mid) Update(u << 1, l, mid, lx, min(mid, rx), val);
if (mid + 1 <= rx) Update(u << 1 | 1, mid + 1, r, max(lx, mid + 1), rx, val);
}
ll Query(int u, int l, int r, int lx, int rx) {
ll res = tag[u] * (rx - lx + 1);
if (lx == l && r == rx) return (res + sum[u]) % Mod;
int mid = (l + r) >> 1;
if (lx <= mid) res += Query(u << 1, l, mid, lx, min(mid, rx));
if (mid + 1 <= rx) res += Query(u << 1 | 1, mid + 1, r, max(mid + 1, lx), rx);
return res % Mod;
}
void Dfs1(int u, int _fa) {
sz[u] = 1;
fa[u] = _fa;
dep[u] = dep[fa[u]] + 1;
for (int i = head[u]; i; i = e[i].nxt)
if (e[i].v != fa[u]) {
int v = e[i].v;
Dfs1(v, u);
if (sz[v] > sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void Dfs2(int u, int _top) {
top[u] = _top;
dfn[u] = ++dfn[0];
if (son[u]) Dfs2(son[u], top[u]);
for (int i = head[u]; i; i = e[i].nxt)
if (e[i].v != fa[u] && e[i].v != son[u]) Dfs2(e[i].v, e[i].v);
}
inline void UpdatePath(int val, int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
Update(1, 1, n, dfn[top[x]], dfn[x], val);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
Update(1, 1, n, dfn[y], dfn[x], val);
}
inline ll QueryPath(int x, int y) {
ll res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
res += Query(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
res += Query(1, 1, n, dfn[y], dfn[x]);
return res % Mod;
}
int main() {
n = Read(), m = Read(), rt = Read(), Mod = Read();
for (int i = 1; i <= n; i++) a[i] = Read();
for (int i = 1; i < n; i++) AddEdge(Read(), Read());
Dfs1(rt, 0);
Dfs2(rt, rt);
for (int i = 1; i <= n; i++) Update(1, 1, n, dfn[i], dfn[i], a[i]);
while (m--) {
int op = Read();
if (op == 1) UpdatePath(Read(), Read(), Read());
else if (op == 2) printf("%lld\n", QueryPath(Read(), Read()));
else if (op == 3) {
int u = Read(), v = Read();
Update(1, 1, n, dfn[u], dfn[u] + sz[u] - 1, v);
} else {
int u = Read();
printf("%lld\n", Query(1, 1, n, dfn[u], dfn[u] + sz[u] - 1));
}
}
return 0;
}
动态规划
01背包
P1048 【NOIP2005 普及组】 采药
constexpr int AwA = 1e2 + 10;
constexpr int QwQ = 1e3 + 10;
int n, m;
int v[AwA], w[AwA];
int f[QwQ];
int main() {
m = Read(), n = Read();
for (int i = 1; i <= n; i++) v[i] = Read(), w[i] = Read();
//这里枚举j要倒序
for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);
printf("%d\n", f[m]);
return 0;
}
完全背包
没找到模板题抱歉喵~
constexpr int AwA = 1e2 + 10;
constexpr int QwQ = 1e3 + 10;
int n, m;
int v[AwA], w[AwA];
int f[QwQ];
int main() {
m = Read(), n = Read();
for (int i = 1; i <= n; i++) v[i] = Read(), w[i] = Read();
//这里枚举j要正序,这是和01背包唯一的一个区别
for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);
printf("%d\n", f[m]);
return 0;
}
字符串
哈希
Luogu P3370 【模板】字符串哈希
constexpr int AwA = 1e4 + 10;
struct Hash {
static constexpr int Mod1 = 1e9 + 7;
static constexpr int Mod2 = 1e9 + 9;
static constexpr int P = 131;
//双哈希
int h1, h2;
//空构造为默认构造
Hash() = default;
//将给定的字符串视为一个P进制数计算哈希值
Hash(const char *s) {
//默认字符串数组下标从1开始
h1 = h2 = 0;
int len = int(strlen(s + 1));
for (int i = 1; i <= len; i++) {
h1 = int((1ll * h1 * P + s[i]) % Mod1);
h2 = int((1ll * h2 * P + s[i]) % Mod2);
}
}
//sort要用,使相等的哈希相邻
inline bool operator<(const Hash &hh) const {
return h1 < hh.h1 || (h1 == hh.h1 && h2 < hh.h2);
}
//unique要用,当且仅当两个哈希值都相等认为两个字符串相等
inline bool operator==(const Hash &hh) const {
return h1 == hh.h1 && h2 == hh.h2;
}
} h[AwA];
int n;
char s[AwA];
int main() {
n = Read();
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
h[i] = Hash(s);
}
sort(h + 1, h + n + 1);
int ans = int(unique(h + 1, h + n + 1) - h - 1);
printf("%d\n", ans);
return 0;
}
哈希表
Luogu P3370 【模板】字符串哈希
typedef unsigned long long ull;
static constexpr int P = 131;
static constexpr int AwA = 1e4 + 10;
class HashTable {
private:
//笔者常用的哈希表质数
static constexpr int Mod = 1e6 + 3;
struct Node {
int nxt;
ull val;
} p[AwA];
int head[Mod], pcnt;
public:
inline void Clear() {
memset(head, 0, sizeof head);
pcnt = 0;
}
//若待插入的数已在哈希表中返回false,否则插入
inline bool Insert(ull val) {
if (Find(val)) return false;
int hs = int(val % Mod);
p[++pcnt] = {head[hs], val};
head[hs] = pcnt;
return true;
}
//查找当前的数是否已在哈希表中
inline bool Find(ull val) {
int hs = int(val % Mod);
for (int i = head[hs]; i; i = p[i].nxt)
if (p[i].val == val) return true;
//未找到
return false;
}
} mp;
inline ull Hash(const char *s) {
ull h = 0;
int len = int(strlen(s + 1));
//自然溢出,即模2的64次方
for (int i = 1; i <= len; i++) h = h * P + s[i];
return h;
}
int n, ans;
char s[AwA];
int main() {
n = Read();
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
if (mp.Insert(Hash(s))) ans++;
}
printf("%d\n", ans);
return 0;
}
KMP
Luogu P3375 【模板】KMP
constexpr int AwA = 1e6 + 10;
int n, m;
char s1[AwA], s2[AwA];
int p[AwA];
inline void Pre() {
p[1] = 0;
for (int i = 2, j = 0; i <= m; i++) {
while (j && s2[j + 1] != s2[i]) j = p[j];
if (s2[j + 1] == s2[i]) j++;
p[i] = j;
}
}
inline void Kmp() {
for (int i = 1, j = 0; i <= n; i++) {
while (j && s2[j + 1] != s1[i]) j = p[j];
if (s2[j + 1] == s1[i]) j++;
if (j == m) printf("%d\n", i - m + 1), j = p[j];
}
}
int main() {
scanf("%s%s", s1 + 1, s2 + 1);
n = int(strlen(s1 + 1)), m = int(strlen(s2 + 1));
Pre();
Kmp();
for (int i = 1; i <= m; i++) printf("%d ", p[i]);
putchar('\n');
return 0;
}
Trie树
Luogu P8306 【模板】字典树
constexpr int AwA = 3e6 + 10;
struct Node {
int ch[62];
int cnt;
} tr[AwA];
int tot;
char s[AwA];
inline int CharToInt(char c) {
if (c <= '9') return c - '0' + 52;
if (c >= 'a') return c - 'a' + 26;
return c - 'A';
}
inline int NewNode() {
tot++;
memset(tr[tot].ch, 0, sizeof(int) * 62);
tr[tot].cnt = 0;
return tot;
}
inline void Insert() {
int u = 1, len = int(strlen(s + 1));
for (int i = 1; i <= len; i++) {
int c = CharToInt(s[i]);
if (!tr[u].ch[c]) tr[u].ch[c] = NewNode();
u = tr[u].ch[c];
tr[u].cnt++;
}
}
int main() {
int T = Read();
while (T--) {
tot = 0;
NewNode();
int n = Read(), m = Read();
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
Insert();
}
while (m--) {
scanf("%s", s + 1);
int u = 1, len = int(strlen(s + 1));
for (int i = 1; i <= len && u; i++) {
int c = CharToInt(s[i]);
u = tr[u].ch[c];
}
printf("%d\n", tr[u].cnt);
}
}
return 0;
}
Manacher
Luogu P3805 【模板】manacher
static constexpr int AwA = 1.1e7 + 10;
int m, n;
//两个数组注意开2倍
char s1[AwA], s[AwA << 1];
int d[AwA << 1];
int ans;
int main() {
scanf("%s", s1 + 1);
m = int(strlen(s1 + 1));
//处理字符串
n = 2 * m + 1;
s[0] = '?', s[1] = '#';
for (int i = 1; i <= m; i++) {
s[i * 2] = s1[i];
s[i * 2 + 1] = '#';
}
s[n + 1] = '\0';
d[1] = 1;
for (int i = 2, l = 1, r = 1; i <= n; i++) {
if (i <= r) d[i] = min(r - i + 1, d[r - i + l]);
while (s[i + d[i]] == s[i - d[i]]) d[i]++;
if (i + d[i] - 1 >= r) r = i + d[i] - 1, l = i - d[i] + 1;
}
//回文子串长度=处理后的回文半径-1
for (int i = 1; i <= n; i++) ans = max(ans, d[i] - 1);
printf("%d\n", ans);
return 0;
}
数学
矩阵快速幂
P3390 【模板】矩阵快速幂文章来源:https://www.toymoban.com/news/detail-844405.html
常用的矩阵操作基本都放在这里了喵文章来源地址https://www.toymoban.com/news/detail-844405.html
typedef long long ll;
constexpr int AwA = 1e2 + 10;
constexpr int Mod = 1e9 + 7;
class Matrix {
private:
//n是行数,m是列数
int n, m;
ll a[AwA][AwA];
public:
Matrix() = default;
Matrix(int n, int m) : n(n), m(m) { memset(a, 0, sizeof a); }
//方便调用
inline ll *operator[](int x) { return a[x]; }
//-同理不写了
inline Matrix operator+(Matrix &m1) const {
Matrix res(n, m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
res[i][j] = (a[i][j] + m1[i][j]) % Mod;
return res;
}
inline Matrix operator*(Matrix &m1) const {
int q = m1.m;
ll r;
Matrix res(n, q);
//换枚举方式减小常数
for (int i = 1; i <= n; i++)
for (int k = 1; k <= m; k++) {
r = a[i][k];
for (int j = 1; j <= q; j++)
res[i][j] = (res[i][j] + r * m1[k][j]) % Mod;
}
return res;
}
inline Matrix operator^(ll k) const {
Matrix res(n, n);
for (int i = 1; i <= n; i++) res[i][i] = 1;
Matrix b(n, n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
b[i][j] = a[i][j];
while (k) {
if (k & 1) res = res * b;
b = b * b;
k >>= 1;
}
return res;
}
};
int main() {
int n = Read();
ll k = Read<ll>();
Matrix a(n, n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
a[i][j] = Read();
Matrix res = a ^ k;
for (int i = 1; i <= n; i++, putchar('\n'))
for (int j = 1; j <= n; j++)
printf("%lld ", res[i][j]);
return 0;
}
到了这里,关于算法竞赛常用模板库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!