KMP 和扩展 KMP
给定一个字符串 。
定义前缀函数 表示 最长的相等的真前缀与真后缀的长度。
规定 。
发现 至多为 (匹配了 上的字符)。
考虑 上的字符不匹配的情况。
那么找到第二长的满足真前缀 真后缀的位置一定最优。
然后会发现这玩意儿其实就是前缀数组的定义。
直接不断跳前缀数组即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 10;
string s, t, g; int f[N];
int main() {
ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> s >> t; g = "$" + t + "#" + s;
int len = g.size() - 1, lent = t.size();
for (int i = 2; i <= len; ++i) {
int pos = i - 1;
while (pos && g[f[pos] + 1] ^ g[i]) pos = f[pos];
if (g[f[pos] + 1] == g[i]) f[i] = f[pos] + 1;
if (f[i] == lent) cout << i - 2 * lent << endl;
}
for (int i = 1; i <= lent; ++i) cout << f[i] << ' ';
return cout << endl, 0;
}
那么扩展 KMP 其实和这个类似。
定义 表示 和 的 LCP(最长公共前缀)长度。
实时维护一个区间 表示当前能匹配的右端点最右的区间。
那么由定义有 。
- 如果当前 。
那么易得 。
根据 ,得到 与 开头的后缀的 LCP 长度。
那么,若 ,那么表示能匹配的长度至多为 。
否则直接暴力向后匹配,更新 。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 4e7 + 10;
string a, b, s; int l, r, resz, resp, z[N];
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> a >> b; s = "#" + b + "$" + a;
int len = s.size() - 1, lena = a.size(), lenb = b.size();
z[1] = lenb, l = r = 1;
for (int i = 2; i <= len; ++i) {
if (i <= r && z[i - l + 1] < r - i + 1) z[i] = z[i - l + 1];
else {
z[i] = max(0ll, r - i + 1);
while (i + z[i] <= len && s[z[i] + 1] == s[i + z[i]]) ++z[i];
}
if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
}
for (int i = 1; i <= lenb; ++i) resz ^= (i * (z[i] + 1));
for (int i = 1; i <= lena; ++i) resp ^= (i * (z[i + lenb + 1] + 1));
return cout << resz << endl << resp << endl, 0;
}
本文作者:MistZero
本文链接:https://www.cnblogs.com/MistZero/p/KMP.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律