题目简要

对于字符串 \(????\) 的每个前缀 \(????[1 ⋯ ????]\),计算出它有多少个 \(border\),满足这些 \(border\) 的长度都不超过该前缀长度的一半。

浅浅谈一下?

至于思路怎么来的,我也不知道?

先考虑一个引论:

\(a\)\(S[1…i]\)\(border\),且满足 \(a\le\frac{i}{2}\),那么一定存在 \(a-1\)\(S[1…i-1]\)\(border\),且同样满足 \(a-1<\frac{i-1}{2}\)

证明

  • 首先按照 \(border\) 的性质,\(a - 1\) 必然是 \(S[1…i-1]\)\(border\)。(如果不懂请手动画图)

  • \(a<=\frac{i}{2}\),所以有 \(a-1 \le \frac{i-2}{2}\),就有 \(a-1 < \frac{i-1}{2}\)

通过这个引论,我们可以再得到一个结论。

  • 如果存在 \(a\) 符合上面的性质,那么有 \(a-1\) 符合上面的性质。

  • 但是如果存在 \(a-1\) 符合上面的性质,不一定有 \(a\) 符合上面的性质。

这样,求 \(S[1...i]\) 时,我们就可以通过枚举 \(S[1...i-1]\) 中符合上面性质的 \(a\) 来看看是否满足上面的性质。

怎么枚举 \(S[1...i-1]\) 中符合上面性质的 \(a\) 呢?

我们记 \(a_0\)\(S[1...i-1]\) 的最长的符合上面性质的 \(border\)

因为 \(KMP\) 问题中有个结论:次长的 \(border\) = \(Next[x]\),其中 \(x\) 为最长的 \(border\)

所以,我们就可以递归枚举 \(S[1...i-1]\) 中符合上面性质的 \(a\)

于是代码就出来了

Code:

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1e6 + 7, Mod = 1e9 + 7;

int T, N[MAXN], A[MAXN], D[MAXN], ans = 1, n;
char S[MAXN];

int main () {
	for (cin >> T; T; T --) {
		cin >> S + 1; n = strlen(S + 1);
		N[1] = 0, D[0] = 0, D[1] = 1; ans = 1;
		for (int i = 2; i <= n; i ++) {
			int p = N[i - 1]; N[i] = 0;
			while (S[p + 1] != S[i] && p != 0) p = N[p];
			if (S[p + 1] == S[i]) N[i] = p + 1;
			D[i] = D[N[i]] + 1;
		}
		memset(A, 0, sizeof(A));
		for (int i = 1; i <= n; i ++) {
			int p = A[i - 1];
			while ((S[p + 1] != S[i] || p * 2 + 2 > i) && p != 0) p = N[p];
			if (S[p + 1] == S[i] && p * 2 + 2 <= i) A[i] = p + 1;
			ans = 1ll * ans * (D[A[i]] + 1) % Mod;
		}
		cout << ans << "\n";
	}
	
	return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿