字符串相关
Preface
字符串操作是 OI
中常见的内容
参考
字典树
Trie
定义
像字典一样的树
引入
用边权来表示字符, 每个节点代表一个状态
疑问
如何存储?
当然是 trie[26][26][26]...
实际上会有很多节点空掉, 如果直接那样开会爆炸而且深度有限制!
所以我们动态开点吧
设定一个 tot
来记录总节点, 插入节点时动态开点
trie[Max][26], tot
判定结束?
- 用
exist[Max]
来记录当前节点是否为结尾节点
实现
constexpr int Max=100000;
struct Trie {
int trie[Max][26], tot;
bool exist[Max]; // 该节点是否为结尾
void insert(char *s, int l) { // 插入字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!trie[p][c]) trie[p][c] = ++tot; // 如果没有,就添加结点
p = trie[p][c];
}
exist[p] = 1;
}
bool find(char *s, int l) { // 查找字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!trie[p][c]) return 0;
p = trie[p][c];
}
return exist[p];
}
};
前缀函数
定义
在第 位时, 子串 最长的相等的真前缀与真后缀的长度。
实现
朴素
直接暴力枚举 更新最大值
优化
当计算到 时
设
当 时
满足定义式, 直接更新为 k+1
即可
可惜大部分情况都不会满足的
这里用 红色 表示 表示的相等情况
我们把前面那 格拿出来看看
现在我用蓝色表示与红色相等
假设此时 , 那么图像就是这样的
我们同时把后面的情况画出来
为什么后面和前面如此相像?
这里的关键是: 从 转移到 (想不通的话, 看回去, 多看几遍)
如此这般, 既然字符串是相等的, 那么后面也存在前 块与后 块相等
那么, 这样可以发现前面第一块红色和后面最后一块蓝色是相等的(动脑想想, 画这个很累的)
如此这般, 状态转移就出来了
从 开始枚举, 所以每次要
枚举 诺不符合第一种直接相等的优质情况那就直接向前找, 即
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 静谧之园!