P3546 PRE-Prefixuffix Sol

这题挺妙的。

有两个串 \(A,B\)\(AB\)\(BA\) 一定循环同构。

利用这个性质可以解决这道题目。

\(f_i\) 表示使得 \(A=s_{1...i},B=s_{i+1...i+x}\) 成立的最大 \(x\)

因为原串的 border \(A\) 很好找,所以寻找中间 \(B\) 的关系。

考虑如何转移,观察 \(f_i\)\(f_{i+1}\)

考虑一个字符 \(c\),有 \(AcB\)\(cBA\) 循环同构,\(A\) 对应 \([1,i]\)

此时除去首、尾的串 \(cB...cB\) 仅剩 \(B...cB_{1...len_b-1}\)

那么原来的 border 为 \(|cB|=len_b+1\),现在的 border 为 \(len_b-1\)

这是最劣情况,也就是说,\(f_{i+1} \ge f_i-2\)

那么就维护一个指针实时统计答案即可。

指针移动次数至多为 \(2n\),复杂度正确。

最后再判一下 \(A\) 是否合法即可计算答案。

注意哈希卡自然溢出。

#include <bits/stdc++.h>
using ll = long long;
using namespace std;

const int N = 1e6 + 10;
const ll bas = 131, Mod = 998244353; int n, dp[N];
ll hsh[N], pw[N]; char str[N];

inline ll qry(int l, int r) {
	return (hsh[r] - hsh[l - 1] * pw[r - l + 1] % Mod + Mod) % Mod;
}

int main() {
	ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
	cin >> n; for (int i = 1; i <= n; ++i) cin >> str[i];
	pw[0] = 1; for (int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * bas % Mod;
	for (int i = 1; i <= n; ++i) hsh[i] = (hsh[i - 1] * bas + str[i]) % Mod;
	for (int len = n / 2; len; --len) {
		dp[len] = dp[len + 1] + 2;
		while (dp[len] + len > n / 2) --dp[len];
		while (dp[len] && qry(len + 1, len + dp[len]) != qry(n - len - dp[len] + 1, n - len)) --dp[len];
	}
	int res = 0;
	for (int i = 1; i <= n / 2; ++i)
		if (qry(1, i) == qry(n - i + 1, n)) res = max(res, i + dp[i]);
	cout << res << endl;
	return 0;
}
posted @ 2023-01-21 00:06  MistZero  阅读(39)  评论(0编辑  收藏  举报