专栏文章

字符串 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,主要是把回文半径的初始值从 11 改为 00 了。因为在某些规则下,单个字符并非回文串。
题目都做了一遍,评价为目前没有难点。

扩展 KMP

CPP
scanf("%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 原理很像,不断扩充右端点,用已知信息扩充得到该点信息。
用途:得到文本串以 ii 为开头的与模式串的 lcp\text{lcp}

CF526D

相当漂亮的题。
首先题目非常抽象,ABAB...A\texttt{ABAB...A} 这种东西相当抽象,我们肯定是希望相邻的是相同的串。所以我们令 C=AB\texttt{C=AB},题目就转化为了 CCC...A\texttt{CCC...A},此时 A\texttt{A}C\texttt{C} 的一个前缀。
首先说一下直观的 Alex_Wei 的做法,就是既然是一个 kk 个相同串组成的前缀,那这个前缀长度肯定是 kk 的倍数,枚举 kk 的倍数 ii,看最小循环节 inxtii - nxt_i 是否是 i/ki / k 的因子。若不是,那这个位置 ii(i/k+1)×k1(i / k + 1) \times k - 1 肯定不满足题意。
若是,还要看后面多少是 C\texttt{C} 的前缀,这个用扩 K\text{K} 随便做下就有了。

另外一个不用扩 K\text{K} 的做法,首先 inxtii - nxt_i 是循环节,然后 i/(inxti)i / (i-nxt_i) 就是循环个数,令他为 ciricir_i
我们需要把 ciricir_i 分给 kk,这样每 ciri/kcir_i / k 个就要并起来,最后剩 cirimodkcir_i \bmod k 个。
如果 imod(inxti)=0i \bmod (i - nxt_i) = 0,说明最后没有多的部分,那 cirimodkciri/kcir_i \bmod k \le cir_i / k 即可。
否则说明最后多了点循环节的前缀,那需要满足 cirimodk<ciri/kcir_i \bmod k < cir_i / k 即可。

评论

0 条评论,欢迎与作者交流。

正在加载评论...