Acwing进阶list
当初五折的时候冲动消费买下的,现在看题单内容挺丰富的,适合打基础,也适合存板子,于是回来刷.
需要学习的知识点包括
1 图论
1.1 网络流
1.1.1 最大流
1.1.1.1 算法模板
1.1.1.2 二分图匹配
1.1.1.3 上下界可行流
1.1.1.4 多源汇最大流
1.1.1.5 关键边
1.1.1.6 最大流判定
1.1.1.7 拆点
1.1.1.8 建图实战
1.1.2 最小割
1.1.2.1 算法模板
1.1.2.2 直接应用
1.1.2.3 最大权闭合图
1.1.2.4 最大密度子图
1.1.2.5 最小点权覆盖集
1.1.2.6 最大点权独立集
1.1.2.7 建图实战
1.1.3 费用流
1.1.3.1 算法模板
1.1.3.2 直接应用
1.1.3.3 二分图最优匹配
1.1.3.4 最大权不相交路径
1.1.3.5 网格图模型
1.1.3.6 拆点
1.1.3.7 上下界可行流
1.2 2-SAT
1.3 朱刘算法
1.4 Prufer编码
2 数据结构
2.1 Splay(一)
2.2 Splay(二)
2.3 树套树
2.4 分块之基本思想、块状链表
2.5 莫队(一)
2.6 莫队(二)
2.7 树链剖分
2.8 动态树
2.9 Dancing Links(一)
2.10 Dancing Links(二)
2.11 左偏树
2.12 后缀数组
2.13 后缀自动机
2.14 点分治和点分树
2.15 CDQ分治
2.16 仙人掌
3 动态规划
3.1 基环树DP
3.2 四边形不等式优化
3.3 插头DP
4 计算几何
4.1 二维计算几何基础
4.2 凸包
4.3 半平面交
4.4 最小圆覆盖
4.5 三维计算几何基础
4.6 三维凸包
4.7 旋转卡壳
4.8 三角剖分
4.9 扫描线
4.10 自适应辛普森积分
5 数学
5.1 莫比乌斯反演
5.2 积性函数
5.3 BSGS
5.4 FFT
5.5 生成函数
5.6 Burnside引理和Polya定理
5.7 斯特林数
5.8 线性基
6 搜索
6.1 模拟退火
6.2 爬山法
7 基础算法
7.1 启发式合并
7.2 manacher算法
7.3 最小表示法
7.4 构造
7.5 打表
习题一共有133道,暂定目标一天3题,最晚在10月底前完成所有题目。
专题1:后缀自动机
模板题
题意:求所有子串len*出现次数的最大值
题解:设f(u)为状态u的出现次数,除了自身作为前缀的1次外,等于所有子状态的出现次数之和,这可以反向建边简单树形dp求出。由于每个状态对应同一个endpos类,只需要用该状态中最长长度乘以出现次数更新答案即可。
//
// Created by vv123 on 2022/8/29.
//
#pragma GCC optimize("Ofast")
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int tot = 1, last = 1;
struct Node {
int len, fa;
int ch[26];
} node[N];
char str[N];
long long f[N], ans;
void extend(int c) {
int p = last, np = last = ++tot;
node[np].len = node[p].len + 1;
f[tot] = 1;
for (; p && !node[p].ch[c]; p = node[p].fa) node[p].ch[c] = np;
if (!p) node[np].fa = 1;
else {
int q = node[p].ch[c];
if (node[q].len == node[p].len + 1) node[np].fa = q;
else {
int nq = ++tot;
node[nq] = node[q]; node[nq].len = node[p].len + 1;
node[q].fa = node[np].fa = nq;
for (; p && node[p].ch[c] == q; p = node[p].fa) node[p].ch[c] = nq;
}
}
}
vector<int> g[N];
void dfs(int u) {
for (auto v : g[u]) {
dfs(v);
f[u] += f[v];
}
if (f[u] > 1) ans = max(ans, f[u] * node[u].len);
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> str;
for (int i = 0; str[i]; i++) extend(str[i] - 'a');
for (int i = 2; i <= tot; i++) {
g[node[i].fa].emplace_back(i);
}
dfs(1);
cout << ans << "\n";
return 0;
}
玄武密码
题意:给定一个字符串s和若干串t,对每一个t求它在s中出现过的最长前缀。
题解:在SAM上遍历即可。
//
// Created by vv123 on 2022/8/29.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 10;
int n, m, last = 1, tot = 1;
char str[N];
struct Node {
int len, fa;
int ch[4];
} node[N << 1];
inline int mp(char ch) {
if (ch == 'E') return 0;
if (ch == 'S') return 1;
if (ch == 'W') return 2;
return 3;
}
void extend(int c) {
int p = last, np = last = ++tot;
node[np].len = node[p].len + 1;
for (; p && !node[p].ch[c]; p = node[p].fa) node[p].ch[c] = np;
if (!p) node[np].fa = 1;
else {
int q = node[p].ch[c];
if (node[q].len == node[p].len + 1) node[np].fa = q;
else {
int nq = ++tot;
node[nq] = node[q]; node[nq].len = node[p].len + 1;
node[q].fa = node[np].fa = nq;
for (; p && node[p].ch[c] == q; p = node[p].fa) node[p].ch[c] = nq;
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m >> str;
for (int i = 0; str[i]; i++) extend(mp(str[i]));
while (m--) {
cin >> str;
int p = 1, res = 0;
for (int i = 0; str[i]; i++) {
int c = mp(str[i]);
if (node[p].ch[c]) p = node[p].ch[c], res++;
else break;
}
cout << res << "\n";
}
return 0;
}
最长公共子串
题意:求若干字符串的最长公共子串,n<=11,len<=10000
题解:考虑SAM跳fa的过程

我们将第一个字符串建出SAM,考虑第二个字符串,依次加入字符,如果可以匹配就往后跳,否则跳fa,以表示丢弃一部分前缀,这样就可以找到一个结束位置p,得到最大的匹配长度。
注意,如果p还有子状态,应当将p的答案传递给所有的子状态。这可以用建反边树形dp一遍来解决。
我们遍历第2~n个串,每个状态的答案取这n-1个结果的最小值,最后取所有状态的最大值,即为最长公共子串。
//
// Created by vv123 on 2022/8/29.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10;
int n;
int tot = 1, last = 1;
struct Node {
int len, fa;
int ch[26];
} node[N];
int ans[N], now[N];
char str[N];
void extend(int c) {
int p = last, np = last = ++tot;
node[np].len = node[p].len + 1;
for (; p && !node[p].ch[c]; p = node[p].fa) node[p].ch[c] = np;
if (!p) node[np].fa = 1;
else {
int q = node[p].ch[c];
if (node[q].len == node[p].len + 1) node[np].fa = q;
else {
int nq = ++tot;
node[nq] = node[q]; node[nq].len = node[p].len + 1;
node[q].fa = node[np].fa = nq;
for (; p && node[p].ch[c] == q; p = node[p].fa) node[p].ch[c] = nq;
}
}
}
vector<int> g[N];
void dfs(int u) {
for (auto v : g[u]) {
dfs(v);
now[u] = max(now[u], now[v]);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> str;
for (int i = 0; str[i]; i++) extend(str[i] - 'a');
for (int i = 1; i <= tot; i++) ans[i] = node[i].len;
for (int i = 2; i <= tot; i++) g[node[i].fa].push_back(i);
for (int k = 2; k <= n; k++) {
cin >> str;
memset(now, 0, sizeof now);
int p = 1, res = 0;
for (int i = 0; str[i]; i++) {
int c = str[i] - 'a';
while (p > 1 && !node[p].ch[c]) p = node[p].fa, res = node[p].len;
if (node[p].ch[c]) p = node[p].ch[c], res++;
now[p] = max(now[p], res);
}
dfs(1);
for (int i = 1; i <= tot; i++) ans[i] = min(ans[i], now[i]);
}
int res = 0;
for (int i = 1; i <= tot; i++) res = max(res, ans[i]);
cout << res << "\n";
return 0;
}

浙公网安备 33010602011771号