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;
}