题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371
题意:把一个数字串A翻过来(abc翻过来为cba)的操作为-A,我们称A-AA这样的串为N-sequence,现在给你一个数字串,问你这个串中最长的N-sequence子串长度
解:可以想到A-A是一个回文串,-AA也是一个回文串,那么首先Manacher跑一遍求出所有回文子串
可以想到任意两个互相覆盖串中心点的回文子串都可以表示成N-sequence
然后大概有三种搞法:
1、时间复杂度O(N*logN),官方题解的方法。
将回文子串以从长到短的顺序加到一个set中(插入值为回文子串的中心位置),插入每个串前询问,该串覆盖范围内离它最远的子串中心位置,来更新答案(因为是从长到短插入set的,所以如果后来的串覆盖了某中心,那么该中心所代表的串一定覆盖后来的串
加了一点注释在代码里面~
2、时间复杂度O(N*logN*logN),比赛的时候写(shui)的。
用分治+rmq乱搞了~价值不大,具体可以看代码
3、时间复杂度O(N^2)。。。吓死了,这个确实有这样子的
有人N^2剪枝过的,有人用了姿势奇怪的线段树,目测理论复杂度O(N^2)
O(N*logN)版本:
1 /* 2 * Problem: hdu5371 Hotaru's problem 3 * Author: SHJWUDP 4 * Created Time: 2015/8/11 星期二 12:25:41 5 * File Name: 1006.cpp 6 * State: Accepted 7 * Memo: Data struct 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <vector> 12 #include <cstring> 13 #include <algorithm> 14 #include <set> 15 16 using namespace std; 17 18 int N; 19 vector<int> arr; 20 namespace Manacher { 21 /** 22 * "abacd " -> "$#a#b#a#c#d# " 23 */ 24 vector<int> arr, p; 25 26 int go(vector<int> & A) { 27 int len=A.size(); 28 arr.resize(A.size()*2+3); 29 p.resize(A.size()*2+3); 30 for(int i=len-1; i>=0; i--) { 31 arr[i*2+2]=A[i]; 32 arr[i*2+1]=-1; 33 } 34 arr[len*2+2]=-2; 35 arr[len*2+1]=-1; 36 arr[0]=-2; 37 len=len*2+2; ///闭区间 38 int maxp=0, id; 39 for(int i=1; i<len-1; i++) { 40 if(i<maxp) p[i]=min(maxp-i, p[id-(i-id)]); 41 else p[i]=1; 42 while(arr[i-p[i]]==arr[i+p[i]]) p[i]++; 43 if(i+p[i]>maxp) { 44 maxp=i+p[i]; 45 id=i; 46 } 47 } 48 49 //可以打印一下p数组,观察下~ 50 vector<pair<int, int> > tmpArr; //pair(回文串长度, 回文串中心位置) 51 for(int i=0; i<len-1; i++) { 52 if(arr[i]!=-1 || p[i]<=1) continue; 53 tmpArr.push_back(make_pair(p[i], i)); 54 } 55 sort(tmpArr.begin(), tmpArr.end(), greater<pair<int, int> >()); //按回文串长从大到小排序 56 set<int> S; 57 int res=0; 58 for(auto & x : tmpArr) { 59 //找当前串左侧覆盖的回文串中心 60 int lim1=x.second-(x.first-1); //左侧 61 auto it1=S.lower_bound(lim1); 62 if(it1!=S.end() && lim1<=(*it1) && (*it1)<x.second) { 63 res=max(res, (x.second-(*it1))/2*3); 64 } 65 //找当前串右侧覆盖的回文串中心 66 int lim2=x.second+(x.first-1); //右侧 67 auto it2=S.upper_bound(x.second+(x.first-1)); 68 if(it2!=S.begin()) --it2; 69 if(it2!=S.end() && x.second<(*it2) && (*it2)<=lim2) { 70 res=max(res, ((*it2)-x.second)/2*3); 71 } 72 S.insert(x.second); 73 } 74 return res; 75 } 76 void print() { 77 for(int i=0; i<(int)arr.size(); i++) { 78 cout<<i<<" "[i==(int)arr.size()-1]; 79 } 80 for(int i=0; i<(int)arr.size(); i++) { 81 cout<<arr[i]<<" "[i==(int)arr.size()-1]; 82 } 83 for(int i=0; i<(int)arr.size(); i++) { 84 cout<<p[i]<<" "[i==(int)arr.size()-1]; 85 } 86 } 87 } 88 int main() { 89 #ifndef ONLINE_JUDGE 90 freopen("in", "r", stdin); 91 // freopen("out", "w", stdout); 92 #endif 93 int T, now=0; 94 scanf("%d", &T); 95 while(T--) { 96 scanf("%d", &N); 97 arr.resize(N); 98 for(int i=0; i<N; i++) { 99 scanf("%d", &arr[i]); 100 } 101 printf("Case #%d: ", ++now); 102 printf("%d ", Manacher::go(arr)); 103 } 104 return 0; 105 }
O(N*logN*logN)版本:
1 /* 2 * Problem: 3 * Author: SHJWUDP 4 * Created Time: 2015/8/11 星期二 12:25:41 5 * File Name: 1006.cpp 6 * State: 7 * Memo: 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <vector> 12 #include <cstring> 13 #include <algorithm> 14 15 using namespace std; 16 17 const int INF=0x7f7f7f7f; 18 19 const int MaxA=2e6+7; 20 21 struct RMQ { 22 int d[MaxA][20]; 23 void init(const vector<int> & A, int n) { 24 for(int i=0; i<n; i++) d[i][0]=A[i]; 25 for(int j=1; (1<<j)<=n; j++) { 26 for(int i=0; i+(1<<j)-1<n; i++) { 27 d[i][j]=max(d[i][j-1], d[i+(1<<(j-1))][j-1]); 28 } 29 } 30 } 31 int query(int L, int R) { 32 int k=0; 33 while((1<<(k+1)) <= R-L+1) k++; 34 return max(d[L][k], d[R-(1<<k)+1][k]); 35 } 36 }; 37 38 int N; 39 vector<int> arr(MaxA); 40 namespace Manacher { 41 /** 42 * "abacd " -> "$#a#b#a#c#d# " 43 */ 44 vector<int> arr(MaxA), p(MaxA), tmpArr(MaxA); 45 RMQ rmq; 46 47 int dc(int lft, int rgt, int x) { 48 if(lft>=rgt) return lft; 49 int mid=(lft+rgt)>>1; 50 int res=-1; 51 if(rmq.query(lft, mid)>=x) res=dc(lft, mid, x); 52 else if(mid+1<=rgt && rmq.query(mid+1, rgt)>=x) res=dc(mid+1, rgt, x); 53 return res; 54 } 55 56 int go(vector<int> & A) { 57 int len=N, lim=len*2+3; 58 for(int i=len-1; i>=0; i--) { 59 arr[i*2+2]=A[i]; 60 arr[i*2+1]=-1; 61 } 62 arr[len*2+2]=-2; 63 arr[len*2+1]=-1; 64 arr[0]=-2; 65 len=len*2+2; ///闭区间 66 int maxp=0, id; 67 for(int i=1; i<len-1; i++) { 68 if(i<maxp) p[i]=min(maxp-i, p[id-(i-id)]); 69 else p[i]=1; 70 while(arr[i-p[i]]==arr[i+p[i]]) p[i]++; 71 if(i+p[i]>maxp) { 72 maxp=i+p[i]; 73 id=i; 74 } 75 } 76 77 for(int i=0; i<lim; i++) { 78 if(arr[i]!=-1) { 79 tmpArr[i]=-INF; 80 } else { 81 tmpArr[i]=i+p[i]-1; 82 } 83 // cout<<tmpArr[i]<<" "[i==(int)p.size()-1]; 84 } 85 86 rmq.init(tmpArr, lim); 87 int res=0; 88 for(int i=0; i<len-1; i++) { 89 if(arr[i]!=-1 || p[i]<=1) continue; 90 // cout<<"to "<<i<<endl; 91 int lft=i-(p[i]-1), rgt=i-1; 92 int tmp=dc(lft, rgt, i); 93 // cout<<"tmp: "<<tmp<<endl; 94 if(tmp!=-1) res=max(res, (i-tmp+1)/2*3); 95 } 96 return res; 97 } 98 void print() { 99 for(int i=0; i<(int)arr.size(); i++) { 100 cout<<i<<" "[i==(int)arr.size()-1]; 101 } 102 for(int i=0; i<(int)arr.size(); i++) { 103 cout<<arr[i]<<" "[i==(int)arr.size()-1]; 104 } 105 for(int i=0; i<(int)arr.size(); i++) { 106 cout<<p[i]<<" "[i==(int)arr.size()-1]; 107 } 108 } 109 } 110 int main() { 111 #ifndef ONLINE_JUDGE 112 freopen("in", "r", stdin); 113 // freopen("out", "w", stdout); 114 #endif 115 int T, now=0; 116 scanf("%d", &T); 117 while(T--) { 118 scanf("%d", &N); 119 for(int i=0; i<N; i++) { 120 scanf("%d", &arr[i]); 121 } 122 printf("Case #%d: ", ++now); 123 printf("%d ", Manacher::go(arr)); 124 } 125 return 0; 126 }