BZOJ2342 [Shoi2011]双倍回文
久了不写manacher又手生了只好抄红书了。
后面的过程就是对每个位置i找一个最远的位置j满足j在i为中心的回文子串的一半以内且j最小。然后直接拿个set就能搞定。
#include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; const int maxn = 500009; char a[maxn]; int d[maxn << 1], n; void manacher() { d[0] = 1; for (int i = 1, j = 0; i < (n << 1) - 1; ++ i) { int p(i >> 1), q(i - p), r(((j + 1) >> 1) + d[j] - 1); if (r < q) d[i] = 0; else d[i] = min(r - q + 1, d[(j << 1) - i]); while (p - d[i] >= 0 && q + d[i] < n && a[p - d[i]] == a[q + d[i]]) ++ d[i]; if (q + d[i] - 1 > r) j = i; } } int pr[maxn]; inline int getr(int _x_) { return _x_+d[((_x_)<<1)+1]; } inline bool cmpRight(const int& a, const int& b) { return getr(a) < getr(b); } set <int> rg; int sov() { int ans(0); for (int i = 0; i < n - 1; ++ i) pr[i] = i; sort(pr, pr + n - 1, cmpRight); for (int i = 0, k = 0; k < n; ++ k) { for (; i < n - 1 && getr(pr[i]) < k; ++ i) rg. erase(pr[i]); set <int> :: iterator it = rg. lower_bound(k - (d[(k << 1) + 1] >> 1)); if (it != rg. end()) ans = max(ans, k - *it); rg. insert(k); } return ans * 4; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif scanf("%d%s", &n, a); manacher(); printf("%d\n", sov()); }