专栏文章
字符串 Alex_Wei
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipon3bk
- 此快照首次捕获于
- 2025/12/03 15:25 3 个月前
- 此快照最后确认于
- 2025/12/03 15:25 3 个月前
Manacher
模板:
CPP#include <bits/stdc++.h>
using namespace std;
const int N = 2.2e7 + 5;
int n, m, ans, R[N];
char s[N], t[N];
int main() {
scanf("%s", s + 1), n = strlen(s + 1);
t[0] = '!', t[m = 1] = '@';
for(int i = 1; i <= n; i++) t[++m] = s[i], t[++m] = '@';
t[++m] = '#';
for(int i = 1, c = 0, r = 0; i < m; i++) {
R[i] = r < i ? 0 : min(R[c * 2 - i], r - i + 1);
while(t[i - R[i]] == t[i + R[i]]) R[i]++;
ans = max(ans, R[i] - 1);
if(i + R[i] - 1 > r) c = i, r = i + R[i] - 1;
}
cout << ans << endl;
return 0;
}
改编自 Alex_Wei,主要是把回文半径的初始值从 改为 了。因为在某些规则下,单个字符并非回文串。
题目都做了一遍,评价为目前没有难点。
扩展 KMP
CPPscanf("%s" , c1 + 1);
scanf("%s" , c2 + 1);
int len1 = strlen(c1 + 1) , len2 = strlen(c2 + 1);
z[1] = len2;
for(int i = 2 , l = 0 , r = 0;i <= len2;i ++) {
z[i] = i > r ? 0 : min(z[i - l + 1] , r - i + 1);
while(c2[1 + z[i]] == c2[i + z[i]]) z[i] ++;
if(i + z[i] - 1 > r) {
l = i , r = i + z[i]- 1;
}
}
for(int i = 1 , l = 0 , r = 0;i <= len1;i ++) {
p[i] = i > r ? 0 : min(z[i - l + 1] , r - i + 1);
while(p[i] < len2 && c2[1 + p[i]] == c1[i + p[i]]) p[i] ++;
if(i + p[i] - 1 > r) {
l = i , r = i + p[i] - 1;
}
}
扩展 KMP 简述:和 Manacher 原理很像,不断扩充右端点,用已知信息扩充得到该点信息。
用途:得到文本串以 为开头的与模式串的 。
CF526D
相当漂亮的题。
首先题目非常抽象, 这种东西相当抽象,我们肯定是希望相邻的是相同的串。所以我们令 ,题目就转化为了 ,此时 是 的一个前缀。
首先说一下直观的 Alex_Wei 的做法,就是既然是一个 个相同串组成的前缀,那这个前缀长度肯定是 的倍数,枚举 的倍数 ,看最小循环节 是否是 的因子。若不是,那这个位置 到 肯定不满足题意。
若是,还要看后面多少是 的前缀,这个用扩 随便做下就有了。
另外一个不用扩 的做法,首先 是循环节,然后 就是循环个数,令他为 。
我们需要把 分给 ,这样每 个就要并起来,最后剩 个。
如果 ,说明最后没有多的部分,那 即可。
否则说明最后多了点循环节的前缀,那需要满足 即可。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...