shjwudp

导航

 

题目链接: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\0" -> "$#a#b#a#c#d#\0"
 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<<"\t\n"[i==(int)arr.size()-1];
 79         }
 80         for(int i=0; i<(int)arr.size(); i++) {
 81             cout<<arr[i]<<"\t\n"[i==(int)arr.size()-1];
 82         }
 83         for(int i=0; i<(int)arr.size(); i++) {
 84             cout<<p[i]<<"\t\n"[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\n", Manacher::go(arr));
103     }
104     return 0;
105 }
View Code

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\0" -> "$#a#b#a#c#d#\0"
 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]<<" \n"[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<<"\t\n"[i==(int)arr.size()-1];
101         }
102         for(int i=0; i<(int)arr.size(); i++) {
103             cout<<arr[i]<<"\t\n"[i==(int)arr.size()-1];
104         }
105         for(int i=0; i<(int)arr.size(); i++) {
106             cout<<p[i]<<"\t\n"[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\n", Manacher::go(arr));
124     }
125     return 0;
126 }
View Code

 

posted on 2015-08-11 21:56  shjwudp  阅读(346)  评论(0编辑  收藏  举报