Border

废话

波论好难,学不懂。

一点一点推罢。

疯狂写博客捏,但是可能有很多笔误(青蛙在我旁边随便一眼都能看到),如果发现了请在评论区中提出!

当然也不排除哪里有些推导过程什么的错了。

Border 的定义

一个字符串的最长真公共前后缀就叫 Border(这个「真」就表示其不和原字符串相同)。

刨开 Border,剩下的一部分被称作 Period。

\[\underbrace{\fcolorbox{000000}{66ccff}{\kern{70pt}}}_{\texttt{Border}}\overbrace{\fcolorbox{000000}{ffffff}{\kern{20pt}}\underbrace{\fcolorbox{000000}{66ccff}{\kern{70pt}}}_{\text{和前面的蓝色部分相同}}}^{\texttt{Period}} \]

Border 是可以有重叠部分的:

\[\underbrace{\fcolorbox{000000}{66ccff}{\kern{70pt}}\overbrace{\fcolorbox{000000}{33667f}{\kern{30pt}}}^{\text{重叠部分}}}_{\texttt{Border}}\underbrace{\fcolorbox{000000}{66ccff}{\kern{70pt}}}_{\texttt{Period}} \]

为什么剩下的部分要叫 Period?因为它是这个字符串的循环节,Border 没有重叠部分的情况是很显然的。

在有重叠的情况下,利用相等关系的传递性,下面三个青色部分是相同的。

\[\fcolorbox{000000}{33667f}{\kern{15pt}}\underbrace{\fcolorbox{000000}{66ccff}{\kern{40pt}}\fcolorbox{000000}{33667f}{\kern{15pt}}}_{\texttt{Period}}\underbrace{\fcolorbox{000000}{66ccff}{\kern{40pt}}\fcolorbox{000000}{33667f}{\kern{15pt}}}_{\texttt{Period}} \]

所以 Period 是这个串的循环节。 如果还有重叠部分可以一直递归下去。

Border 的性质和定理

因为 Border 和 Period 关联比较大,所以也会有很多关于 Period 的性质和定理。

Border 的 Border 是 Border

\(\operatorname{Border}(S)\) 表示字符串 \(S\) 的所有 Border 组成的集合,令 \(\operatorname{maxBorder}(S)\) 表示字符串 \(S\) 长度最大的 Border。

那么有:

\[\operatorname{Border}(S) = \operatorname{Border}(\operatorname{maxBorder}(S)) \cup \left\{\operatorname{maxBorder}(S)\right\} \]

就是一个字符串所有的 Border 是由它最大的 Border 和这个 Border 的所有 Border 组成的。

换句话说就是:Border 的 Border 是 Border。

\[\underbrace{\overbrace{\fcolorbox{000000}{33667f}{\kern{45pt}}}^{\texttt{Border}\text{的}\texttt{Border}}\fcolorbox{000000}{66ccff}{\kern{15pt}}\fcolorbox{000000}{33667f}{\kern{45pt}}}_{\texttt{Border}}\fcolorbox{000000}{ffffff}{\kern{15pt}}\fcolorbox{000000}{33667f}{\kern{45pt}}\fcolorbox{000000}{66ccff}{\kern{15pt}}\overbrace{\fcolorbox{000000}{33667f}{\kern{45pt}}}^{\text{与青色部分相同}} \]

(有重叠的情况懒得画了。)

Border 的前半部分的两段 Border 相同,而 Border 本身的两段也相同,从而前半段的 Border 和后半段的 Border 相同,所以是原字符串的 Border。

由此可见,Border 的 Border 可以利用相等关系的传递性,来证明是原字符串的另一个 Border。

而且并不存在一个 Border,使得它不是 \(\operatorname{maxBorder}(S)\) 且不属于 \(\operatorname{Border}(S)\)

若存在,则它必定比 \(\operatorname{maxBorder}(S)\) 短,而它又是原串的 Border,所以它分别和 \(\operatorname{maxBorder}(S)\) 的左右两段相同,所以它又是 \(\operatorname{maxBorder}(S)\) 的 Border,矛盾。

弱周期定理(Weak Periodicity Lemma)

若字符串 \(S\) 存在两个长度分别为 \(p\)\(q\) 的 Period,且 \(p + q \leqslant |S|\),那么 \(S\) 还存在长度为 \(\gcd(p, q)\) 的 Period。

证明:更相减损术。

\[\overbrace{\fcolorbox{000000}{66ccff}{\kern{36pt}}}^{\texttt{p}}\fcolorbox{000000}{66ccff}{\kern{36pt}}\fcolorbox{000000}{66ccff}{\kern{36pt}} \fcolorbox{000000}{ffffff}{\kern{26pt}}\\[5pt] \overbrace{\fcolorbox{000000}{33667f}{\kern{24pt}}}^{\texttt{q}} \fcolorbox{000000}{33667f}{\kern{24pt}} \fcolorbox{000000}{33667f}{\kern{24pt}} \fcolorbox{000000}{33667f}{\kern{24pt}} \fcolorbox{000000}{33667f}{\kern{24pt}} \fcolorbox{000000}{ffffff}{\kern{2pt}}\\[5pt] \underbrace{\fcolorbox{000000}{3f48cc}{\kern{10pt}}}_{\texttt{d}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{3f48cc}{\kern{10pt}}\fcolorbox{000000}{ffffff}{\kern{8pt}} \]

若一个字符串有长度为 \(len\) 的 Period,那么对于所有的 \(i(1 \leqslant i \leqslant |S| - len)\),都有 \(S_{i} = S_{i + len}\),或是对于所有的 \(i(len < i \leqslant |S|)\),有 \(S_{i - len} = S_{i}\)(这两个是等价的)。反推也成立。

不妨设 \(p > q\),令 \(d = p - q\),那么有:

  1. \(i \leqslant q\) 时,\(S_{i} = S_{i + p} = S_{i + p - q} = S_{i + d}\)
  2. \(q < i \leqslant p\) 时,\(S_{i} = S_{i - q} = S_{i - q + p} = S_{i - d}\)
  3. \(p < i\) 时,\(S_{i} = S_{i - np} = S_{i - mq}\),可以转化为上面两种情况。

所以 \(S\) 存在长度为 \(d\) 的循环节,这个过程可以一直递归直至 \(p = q\)

同时还有一个周期定理(Periodicity Lemma),它的条件变为了 \(p + q - \gcd(p, q) \leqslant |S|\),其余不变。但是证明起来困难很多并且用处不大,就暂时没学。

前缀的 Period 是 Period

(当然是有条件的。)

若字符串 \(S\) 存在长度为 \(p\) 的周期和一个前缀 \(T\),且 \(T\) 存在长度为 \(q\) 的周期。若 \(|T| \geqslant p\)\(q | p\),那么 \(S\) 也存在长度为 \(q\) 的周期。

\[\overbrace{\fcolorbox{000000}{33667f}{\kern{25pt}}}^{\texttt{q}} \fcolorbox{000000}{33667f}{\kern{25pt}} \fcolorbox{000000}{ffffff}{\kern{2pt}} \kern{28pt}\\[5pt] \overbrace{\fcolorbox{000000}{66ccff}{\kern{55pt}}}^{\texttt{p}} \fcolorbox{000000}{66ccff}{\kern{55pt}}\fcolorbox{000000}{66ccff}{\kern{55pt}} \fcolorbox{000000}{ffffff}{\kern{30pt}}\\[5pt] \underbrace{\fcolorbox{000000}{33667f}{\kern{25pt}} \fcolorbox{000000}{33667f}{\kern{25pt}} \fcolorbox{000000}{ffffff}{\kern{2pt}}}_{T} \kern{52pt} \fcolorbox{000000}{33667f}{\kern{25pt}} \fcolorbox{000000}{33667f}{\kern{25pt}} \fcolorbox{000000}{ffffff}{\kern{2pt}} \kern{27pt} \]

青色部分(\(T\) 的 Period)正好可以填充满一个蓝色部分(\(S\) 的 Period),而蓝色部分又是 \(S\) 的 Period,所以每一个蓝色部分都是由若干个完整的青色部分组成的(除了最后一部分可能不完整),所以青色部分也是 \(S\) 的 Period。

Border 中的等差数列

  1. 若字符串 \(S, T\) 满足 \(|T| \geqslant \dfrac{|S|}{2}\),则 \(T\)\(S\) 中的匹配位置可以排成一个等差数列。

首先不考虑 \(S\) 中没有被任何匹配子串覆盖到位置,相当于把开始和结束的一段丢掉(因为 \(|T| \geqslant \dfrac{|S|}{2}\) 所以不可能存在中间一段没有被覆盖而两旁被覆盖的情况)。

考虑第一个匹配位置,第二个匹配位置以及最后一个匹配位置。

(若没有三个及以上的匹配位置那么结论显然成立,就不讨论了。)

\[\fcolorbox{000000}{66ccff}{\kern{180pt}}\\[5pt] \fcolorbox{000000}{33667f}{\kern{80pt}}\kern{100pt}\\[5pt] \xleftrightarrow{\kern{12.5pt}\texttt{p}\kern{12.5pt}}\fcolorbox{000000}{33667f}{\kern{80pt}}\kern{60pt}\\[5pt] \cdots\\ \kern{40pt}\xleftrightarrow{\kern{23pt}\texttt{q}\kern{23pt}}\fcolorbox{000000}{33667f}{\kern{80pt}}\\ \]

令第一个匹配位置和第二个匹配位置之间的距离为 \(p\),第二个匹配位置和最后一个匹配位置之间的距离为 \(q\)

考虑第一个匹配子串和第二个匹配子串的「并集」, \(T\) 是它的 Border,所以它存在长度为 \(p\) 的 Period。

\(T\) 也是这个「并集」的前缀,所以 \(T\) 也拥有长度为 \(p\) 的 Period。

(上面这一点感觉很显然就没打算单独讲。)

同理可得 \(T\) 还存在长度为 \(q\) 的 Period。

而因为 \(p + q + |T| = |S| \Leftrightarrow p + q = |S| - |T| \leqslant 2|T| - |T| = |T|\)

由弱周期定理(WPL)可知,\(T\) 还存在长度为 \(\gcd(p, q)\) 的 Period。

\(g = \gcd(p, q)\)\(T\) 的最短 Period 长度为 \(l\)

那么肯定有 \(l | p\),否则可以利用弱周期定理继续构造更短的 \(l\)

\(l < p\),那么显然可以构造出比第二个匹配位置更靠前的匹配,或者说是更小的 \(p\)

\[\fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{ffffff}{\kern{1pt}}\\ \kern{21pt}\xleftrightarrow{\kern{4pt}\texttt{l}\kern{4pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{ffffff}{\kern{1pt}}\\ \kern{43pt}\xleftrightarrow{\kern{14pt}\texttt{p}\kern{14pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{66ccff}{\kern{15pt}} \fcolorbox{000000}{ffffff}{\kern{1pt}}\\ \]

所以 \(p = l\),进而有 \(p = l = g\),所以 \(p | q\)

又因为 \(S\)\(T\) 完全覆盖了,所以对于任意的 \(i(i \leqslant |S| - p)\),都有 \(S_{i} = S_{i + p}\),所以 \(S\) 也有长度为 \(p\) 的 Period 且这是最短的 Period。

所以 \(S\) 中所有的 \(T\) 的匹配位置可以排成一个等差数列,其公差为 \(p\)

  1. 字符串 \(S\) 中所有长度大于等于 \(\dfrac{|S|}{2}\) 的 Border 的长度可以排成一个等差数列。

考虑 \(\operatorname{maxBorder}(S)\) 和任意一个非 \(\operatorname{maxBorder}(S)\) 的长度大于等于 \(\dfrac{|S|}{2}\) 的 Border。

(若不存在两个及以上的 Border 那么显然成立,不讨论。)

令它们对应的 Period 长度分别为 \(p\)\(q\)

\[\fcolorbox{000000}{ffffff}{\kern{136pt}}\\[5pt] \fcolorbox{000000}{66ccff}{\kern{100pt}} \underbrace{\fcolorbox{000000}{00a8f3}{\kern{30pt}}}_{\texttt{p}}\\[5pt] \fcolorbox{000000}{3f48cc}{\kern{80pt}} \underbrace{\fcolorbox{000000}{33667f}{\kern{50pt}}}_{\texttt{q}}\\[5pt] \]

因为两个 Border 的长度都大于 \(\dfrac{|S|}{2}\),所以 \(p, q \leqslant |S| - \dfrac{|S|}{2} = \dfrac{|S|}{2}\),所以 \(p + q \leqslant |S|\)

利用弱周期定理(WPL)可知,\(\gcd(p, q)\) 也是 \(S\) 的 Period,若 \(\gcd(p, q) < p < q\),那么 \(S\) 应有更长的 Border,与我们开始所取的 \(\operatorname{maxBorder}(S)\) 矛盾,所以 \(\gcd(p, q) = p\),所以 \(p | q\)

而这个结论是对所有长度大于等于 \(\dfrac{|S|}{2}\) 的 Border 成立的,所以这些 Border 对应的 Period 的长度显然都是 \(p\) 的倍数,进而得到这些 Border 的长度可以排成公差为 \(p\) 的等差数列的结论。

实际上,这个结论可以之际推到长度大于等于 \(|S| - p\) 的 Border,因为这些 Border 都满足弱周期定理的使用条件。

拓展结论:一个字符串 \(S\) 的所有 Border 的长度可以划分成 \(\mathcal{O}(\log |S|)\) 个等差数列。

这个拓展结论其实挺显然的,不证了。

如何求每个前缀的 maxBorder

详见 「BJWC2018 Border 的四种求法」一题。

朴素的求法是 \(\mathcal{O}(n^{2})\) 的。

注意到小标题「前缀」这一限定,令 \(nxt_{i}\) 表示 \(\operatorname{maxBorder}(S[1 .. i])\) 的长度(也对应着靠前的 Border 的结束位置)。若我们已知 \(nxt_{1 \sim i - 1}\),那么可以快速求出 \(nxt_{i}\)

KMP 包含了这一部分,这里不细讲,贴一个远古博客的链接

而这个 \(nxt_{i}\) 常常会被称为 \(fail\) 指针,因为在字符串匹配失败时就是利用它快速跳转的。

若把每一对 \((fail_{i}, i)\) 看作一条树上的边,那么所有的边就组成了一棵失配树,总共有 \(n + 1\) 个点和 \(n\) 条边,有时候将题目放到失配树上来做会直观许多。

一个点到根的路径就包含了它所有的 Border。

每一个前缀在 \(S\) 中的出现次数就是其子树大小。

应该还有很多性质,但是还不了解。

习题

做一题写一题,咕咕咕。

Luogu P3193 [HNOI2008] GT考试

考虑对匹配的过程 dp。

观察到 \(M\) 最大只有 \(20\),所以可以直接以当前匹配长度来作为状态。

\(dp_{i, j}\) 表示以第 \(i\) 个字符结束的后缀的最长匹配长度。

\(cnt_{i, j}\) 表示在匹配长度为 \(i\) 的后缀后加一个字符使得它最长匹配后缀的长度变为 \(j\) 的方案数。

那么有转移式:

\[dp_{i, j} = \sum\limits_{k = 0}^{m - 1}cnt_{k, j}dp_{i - 1, k} \]

对于每一个 \(i\),转移的方式都没变,所以可以用矩阵来加速。

如何求 \(cnt_{i, j}\)?直接枚举 \(i\) 和下一个字符,按照 KMP 的方式来进行匹配,假设最后的匹配长度为 \(k\),那么令 \(cnt_{i, k} \leftarrow cnt_{i, k} + 1\)

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, mod, now, ans, nxt[25];
string s;
struct matrix {
	int val[20][20];
	matrix(int v = 0) {
		for(int i = 0; i < m; ++i) {
			for(int j = 0; j < m; ++j) {
				val[i][j] = (i == j ? v : 0);
			}
		}
	}
	void operator *= (const matrix& _) {
		static matrix res;
		for(int i = 0; i < m; ++i) {
			for(int j = 0; j < m; ++j) {
				res.val[i][j] = 0;
				for(int k = 0; k < m; ++k) {
					res.val[i][j] += val[i][k] * _.val[k][j] % mod;
				}
				res.val[i][j] %= mod;
			}
		}
		memcpy(val, res.val, sizeof(val));
	}
} a, res;
matrix ksm(matrix& v, int y) {
	matrix ret(1), x = v;
	while(y) {
		if(y & 1) ret *= x;
		x *= x;
		y >>= 1;
	}
	return ret;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> m >> mod >> s;
	s = "V" + s;
	for(int i = 2, j = 0; i <= m; ++i) {
		while(j && s[j + 1] != s[i]) j = nxt[j];
		if(s[j + 1] == s[i]) ++j;
		nxt[i] = j;
	}
	for(int i = 0; i < m; ++i) {
		for(char j = '0'; j <= '9'; ++j) {
			now = i;
			while(now && s[now + 1] != j) now = nxt[now];
			if(s[now + 1] == j) ++now;
			if(now < m) ++a.val[i][now];
		}
	}
	res = ksm(a, n);
	for(int i = 0; i < m; ++i) ans += res.val[0][i];
	cout << ans % mod;
	return 0;
}

Luogu P3435 [POI2006] OKR-Periods of Words

题目就是让你求每个前缀的最大真循环节长度之和(如不存在则为 \(0\))。

循环节长度显然可以转化为 Border 长度。

但是题目还有一个条件:\(a\)\(Q + Q\) 的前缀。

其实这个条件没什么用,它等价于 Border 长度小于等于前缀长度的一半。

如果有 Border 长度大于前缀长度的一半,那么两端 Border 的重合部分显然也是一个 Border:

\[\underbrace{\fcolorbox{000000}{33667f}{\kern{18pt}}}_{\texttt{Border}}\fcolorbox{000000}{66ccff}{\kern{40pt}}\underbrace{\fcolorbox{000000}{33667f}{\kern{18pt}}}_{\texttt{Border}}\fcolorbox{000000}{66ccff}{\kern{40pt}}\underbrace{\fcolorbox{000000}{33667f}{\kern{18pt}}}_{\texttt{Border}} \]

所以这一点就不需要考虑了,现在我们要求:每个前缀的最短 Border 长度。

因为「Border 的 Border 是 Border」,所以可以用 KMP 求出 \(nxt\) 再不停地跳,直到跳到最短的 Border 为止。

这个过程会比较慢,可以用记忆化。

另外一个方法是构建失配树,发现「一个前缀的最短 Border」就是它的最浅非根祖先。

所以可以在失配树上搜索,记录子树的最浅非根祖先,便搜索边统计答案即可。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, nxt[1000005], siz[1000005];
ll ans;
vector<int> g[1000005];
string s;
void dfs(int now, int rt) {
	if(!rt) rt = now;
	if(now) ans += now - rt;
	for(const auto& i : g[now]) {
		dfs(i, rt);
	}
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> s;
	s = "V" + s;
	g[0].push_back(1);
	for(int i = 2, j = 0; i <= n; ++i) {
		while(j && s[j + 1] != s[i]) j = nxt[j];
		if(s[j + 1] == s[i]) ++j;
		nxt[i] = j;
		g[nxt[i]].push_back(i);
	}
	dfs(0, 0);
	cout << ans;
	return 0;
}

Luogu P2375 [NOI2014] 动物园

感受失配树的强大!

显然 \(num_{i}\) 就是 \(i\) 到根的路径上(根除外)编号小于等于 \(\dfrac{i}{2}\) 的点的数量(Border 不重叠那么肯定长度小于字符串的一半)。

那么可以用树状数组来维护结点数量的前缀和,具体地,进入结点 \(i\) 时将其在树状数组中的值 \(+1\),退出时 \(-1\),统计答案则直接 \(ask(i / 2)\) 即可。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int mod = 1000000007;
int t, n, nxt[1000005], num[1000005], c[1000005];
ll ans;
vector<int> g[1000005];
string s;
int lowbit(int x) {return x & -x;}
void update(int x, int v) {
	while(x <= 1000000) {
		c[x] += v;
		x += lowbit(x);
	}
}
int ask(int x) {
	int ret = 0;
	while(x) {
		ret += c[x];
		x -= lowbit(x);
	}
	return ret;
}
void dfs(int now) {
	num[now] = ask(now >> 1);
	if(now) update(now, 1);
	for(const auto& i : g[now]) {
		dfs(i);
	}
	if(now) update(now, -1);
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> t;
	while(t--) {
		cin >> s;
		n = s.length();
		s = "V" + s;
		for(int i = 0; i <= n; ++i) g[i].clear();
		for(int i = 2, j = 0; i <= n; ++i) {
			while(j && s[j + 1] != s[i]) j = nxt[j];
			if(s[j + 1] == s[i]) ++j;
			nxt[i] = j;
		}
		for(int i = 1; i <= n; ++i) g[nxt[i]].push_back(i);
		dfs(0);
		ans = 1;
		for(int i = 1; i <= n; ++i) ans = ans * (num[i] + 1ll) % mod;
		cout << ans << '\n';
	}
	return 0;
}

Luogu P3426 [POI2005] SZA-Template

如果这个印章能覆盖整个字符串,那么肯定在字符串的开头结尾都要印一次,所以它肯定是原串的一个 Border!

现在我们随便截取一个 Border,怎么判断它是否合法呢?

首先在原串中找到所有的这个 Border 的匹配串,在上面印个章,如果最后原串每个位置都被盖到了,那么它就是合法的。

注意到每个匹配串都代表着一个前缀,这个 Border 也是这个前缀的 Border。

把这一关系放到失配树上,就是看子树内的所有相邻位置的距离最大值。

set 可以轻松做到 \(\mathcal{O}(n \log n)\) 的复杂度。

但是如果只删不加,就可以改用链表,从而做到 \(\mathcal{O}(n)\)

每次搜索儿子先删掉不在点 \(n\) 到根上的链的子树,再访问链上的儿子即可。

Code:

#include <bits/stdc++.h>
using namespace std;
int n, mx, l[500005], r[500005], nxt[500005];
bool flag[500005];
string s;
vector<int> g[500005];
int dfs(int now) {
	if(flag[now] && mx <= now) return now;
	for(const auto& i : g[now]) {
		if(!flag[i]) {
			dfs(i);
		}
	}
	mx = max(mx, r[now] - l[now]);
	r[l[now]] = r[now], l[r[now]] = l[now];
	for(const auto& i : g[now]) {
		if(flag[i]) {
			auto res = dfs(i);
			if(res) return res;
		}
	}
	return 0;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> s;
	n = s.length();
	s = "V" + s;
	for(int i = 2, j = 0; i <= n; ++i) {
		while(j && s[j + 1] != s[i]) j = nxt[j];
		if(s[j + 1] == s[i]) ++j;
		nxt[i] = j;
	}
	for(int i = 1; i <= n; ++i) {
		g[nxt[i]].push_back(i);
		l[i] = i - 1, r[i] = i + 1;
	}
	for(int now = n; now; now = nxt[now]) {
		flag[now] = true;
	}
	cout << dfs(0);
	return 0;
}
posted @ 2024-02-25 20:00  A_box_of_yogurt  阅读(32)  评论(0编辑  收藏  举报
Document