题目大意:
就是现在给出一个长度为N <= 100000的数列, 每个数都是10^9以内的正整数, 现在要在这个数列中找出最长的形似ww^w的串, w^是w反序写出来的串
大致思路:
很常见的一个Manacher + Set维护的类型的题....
首先用Manacher处理出每个位置为中心的回文半径
然后从左往右扫, 每次对于当前位置 i, 其半径覆盖到的最右位置 (i, i + R[i] - 1)添加到set里(作为左中心)
那么对于位置i, 要使其作为右中心的话, 左中心的最右覆盖位置必须能覆盖到这个位置, 于是将set中不能覆盖到这个位置的都删掉
然后查询set中最左边的能够覆盖这个位置的做中心 i', 于是 (i - i')/2就是中间w'的最大长度L, ans就是所有3*L中的最大值, 时间复杂度O(nlogn), n为序列长度
比赛的时候还WA了一次.....ans初始写的-1....真是醉了...
代码如下:
Result : Accepted Memory : 8380 KB Time : 1201 ms
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <iostream> #include <algorithm> #include <set> using namespace std; #define maxn 100200 int n; int in[maxn]; int s[maxn << 1]; int R[maxn << 1]; void Manacher(int *s, int *R, int n) { int p = 0, mx = 0; R[0] = 1; for(int i = 1; i <= n; i++) { if(mx > i) R[i] = min(R[2*p - i], mx - i); else R[i] = 1; while(s[i - R[i]] == s[i + R[i]]) R[i]++; if(i + R[i] > mx) mx = i + R[i], p = i; } return; } set<pair<int, int> > S[2]; set<pair<int, int> > :: iterator it; int ac = 0; int main() { int T; scanf("%d", &T); while(T--) { ac ++; scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &in[i]); s[0] = -2; for(int i = 0; i < n; i++) s[2*i + 1] = -10, s[2*i + 2] = in[i]; s[2*n + 1] = -10; s[2*n + 2] = -1; //for(int i = 0; i < 2*n + 3; i++) //cout<<s[i]<<" "; //cout<<endl; Manacher(s, R, 2*n + 2); // for(int i = 0; i < 2*n +3; i++) // cout<<R[i]<<endl; //for(int i = 0; i < 2*n +2 ; i++) cout<<R[i]<<endl; S[1].clear(); S[0].clear();//S[0] (i + r, i)..., S[1](i, i + r) int ans = 0; for(int i = 3; i < 2*n + 1; i += 2) { int L = i; while(!S[0].empty() && (*S[0].begin()).first < L) { S[1].erase(make_pair((*S[0].begin()).second, (*S[0].begin()).first)); S[0].erase(S[0].begin()); } L = i - R[i] + 1; it = S[1].lower_bound(make_pair(L, 0)); if(it != S[1].end()) { int now = (*it).first; ans = max(ans, (i - now) / 2 *3); } S[1].insert(make_pair(i, i + R[i] - 1)); S[0].insert(make_pair(i + R[i] - 1, i)); } printf("Case #%d: %d\n",ac, ans); } return 0; }