求出每个点的最大回文长度。
然后转换成线段互相覆盖的最大长度。
然后离线之后用线段树 或者 set维护一下就好了。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 2e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int n, a[N], b[N]; int maxLen[N]; struct StrHash { const ull B = 23333; ull hsL[N], hsR[N], Pow[N]; void build(int *a, int n) { Pow[0] = 1; hsR[n + 1] = 0; for(int i = 1; i <= n; i++) { hsL[i] = hsL[i - 1] * B + a[i]; Pow[i] = Pow[i - 1] * B; } for(int i = n; i >= 1; i--) { hsR[i] = hsR[i + 1] * B + a[i]; } } ull getLVal(int L, int R) { return hsL[R] - hsL[L - 1] * Pow[R - L + 1]; } ull getRVal(int L, int R) { return hsR[L] - hsR[R + 1] * Pow[R - L + 1]; } } ha; struct SegmentTree { #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 int mx[N << 2]; void build(int l, int r, int rt) { mx[rt] = 0; if(l == r) return; int mid = l + r >> 1; build(lson); build(rson); } void update(int p, int val, int l, int r, int rt) { if(l == r) { mx[rt] = val; return; } int mid = l + r >> 1; if(p <= mid) update(p, val, lson); else update(p, val, rson); mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); } int query(int R, int l, int r, int rt) { if(mx[rt] < R) return -1; if(l >= R) return -1; if(l == r) return l; int mid = l + r >> 1; if(mx[rt << 1] >= R) return query(R, lson); else return query(R, rson); } } Tree; struct Line { int l, r; bool operator < (const Line &rhs) const { return l < rhs.l; } } L[N]; int main() { int T; scanf("%d", &T); for(int cas = 1; cas <= T; cas++) { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = 1; i <= n; i++) { b[i << 1] = a[i]; } n = 2 * n + 1; for(int i = 1; i <= n; i += 2) { b[i] = 100000001; } ha.build(b, n); Tree.build(1, n, 1); int Ltot = 0; for(int i = 1; i <= n; i += 2) { int low = 1, high = min(i, n - i + 1); while(low <= high) { int mid = low + high >> 1; if(ha.getLVal(i - mid + 1, i) == ha.getRVal(i, i + mid - 1)) { maxLen[i] = mid; low = mid + 1; } else { high = mid - 1; } } L[++Ltot] = Line{i - maxLen[i] + 1, i}; } for(int i = 1; i <= n; i += 2) { Tree.update(i, i + maxLen[i] - 1, 1, n, 1); } int ans = 0; sort(L + 1, L + 1 + Ltot); for(int i = 1, j = 1; i <= Ltot; i++) { int l = L[i].l, r = L[i].r; if(l == r) continue; while(j <= n && j < l) { Tree.update(j, 0, 1, n, 1); j += 2; } int p = Tree.query(r, 1, n, 1); if(~p) { chkmax(ans, (r - p) >> 1); } } printf("Case #%d: %d\n", cas, ans * 3); } return 0; } /* */