HDU 5558 后缀数组+二分

题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j。

可以在rank数组中二分,在1-rank[i-1]中二分最接近i的j使得sa[j]小于i,通俗地说就是rank比的rank[i]小,并且位于i之前的后缀。因为这个是左边最接近rank[i]的,所以与suffix[i]的最长公共前缀一定是满足最大的。接下来再根据得到的LCP值,二分一个最小的j。同理,再从rank[i+1]到rank[n]中作类似二分。两者结合得到当前的K和T。

其实这道题中间过程也可以不用二分,直接向左右暴力扫。速度会快很多。

  1 #include <iostream>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <string>
  5 #include <string.h>
  6 #include <stdio.h>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <set>
 11 #include <cmath>
 12 #include <ctime>
 13 #include <cassert>
 14 #include <sstream>
 15 using namespace std;
 16 
 17 const int N=1e5+10;
 18 
 19 
 20 int MIN(int a,int b) {
 21     return a<b?a:b;
 22 }
 23 int MAX(int a,int b) {
 24     return a>b?a:b;
 25 }
 26 
 27 int val[N];
 28 struct RMQ {
 29     int dp[N][22];
 30     int (*cmp) (int,int);
 31     void setMin() {
 32         cmp=MIN;
 33     }
 34     void setMax() {
 35         cmp=MAX;
 36     }
 37     void init(int n,int *val) {
 38         for (int i=0; i<=n; i++)
 39             dp[i][0]=val[i];
 40         for (int j=1; (1<<j)<=n; j++) {
 41             int k=1<<(j-1);
 42             for (int i=0; i+k<=n; i++)
 43                 dp[i][j]=cmp(dp[i][j-1],dp[i+k][j-1]);
 44         }
 45     }
 46     int query(int a,int b) {
 47         if (a>b) swap(a,b);
 48         int dis=b-a+1;
 49         int k=log((double)dis)/log(2.0);
 50         return cmp(dp[a][k],dp[b-(1<<k)+1][k]);
 51     }
 52 } rmq;
 53 
 54 char s[N];
 55 struct SuffixArray {
 56     int wa[N], wb[N], cnt[N], wv[N];
 57     int rk[N], height[N];
 58     int sa[N];
 59     bool cmp(int r[], int a, int b, int l) {
 60         return r[a] == r[b] && r[a+l] == r[b+l];
 61     }
 62     void calcSA(char r[], int n, int m) {
 63         int i, j, p, *x = wa, *y = wb;
 64         for (i = 0; i < m; ++i) cnt[i] = 0;
 65         for (i = 0; i < n; ++i) cnt[x[i]=r[i]]++;
 66         for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
 67         for (i = n-1; i >= 0; --i) sa[--cnt[x[i]]] = i;
 68         for (j = 1, p = 1; p < n; j *= 2, m = p) {
 69             for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
 70             for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
 71             for (i = 0; i < n; ++i) wv[i] = x[y[i]];
 72             for (i = 0; i < m; ++i) cnt[i] = 0;
 73             for (i = 0; i < n; ++i) cnt[wv[i]]++;
 74             for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
 75             for (i = n-1; i >= 0; --i) sa[--cnt[wv[i]]] = y[i];
 76             for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
 77                 x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
 78         }
 79     }
 80     void calcHeight(char r[], int n) {
 81         int i, j, k = 0;
 82         for (i = 1; i <= n; ++i) rk[sa[i]] = i;
 83         for (i = 0; i < n; height[rk[i++]] = k)
 84             for (k?k--:0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k++);
 85     }
 86     int lcp(int a,int b,int len) {
 87         if (a==b) return len-a;
 88         int ra=rk[a],rb=rk[b];
 89         if (ra>rb) swap(ra,rb);
 90         return queryST(ra+1,rb);
 91     }
 92     int st[N][22];
 93     int preLog2[N];
 94     void initST(int n) {
 95         for (int i=1; i<=n; i++)
 96             st[i][0]=height[i];
 97         for (int j=1; (1<<j)<=n; j++) {
 98             int k=1<<(j-1);
 99             for (int i=1; i+k<=n; i++)
100                 st[i][j]=min(st[i][j-1],st[i+k][j-1]);
101         }
102         preLog2[1]=0;
103         for(int i=2;i<=n;i++){
104             preLog2[i]=preLog2[i-1]+((i&(i-1))==0);
105         }
106     }
107     int queryST(int a,int b) {
108         if (a>b) swap(a,b);
109         int dis=b-a+1;
110         int k=preLog2[dis];
111         return min(st[a][k],st[b-(1<<k)+1][k]);
112     }
113     void solve(int n) {
114         calcSA(s,n+1,128);
115         calcHeight(s,n);
116         initST(n);
117         rmq.setMin();
118         rmq.init(n,sa);
119         printf("-1 %d\n",s[0]);
120         int i=1;
121         while (i<n) {
122             int l=1,r=rk[i]-1;
123             int k=-1,t=s[i];
124             int minIndex=-1;
125             while (l<=r) {
126                 int mid=(l+r)>>1;
127                 int minSA=rmq.query(mid,rk[i]-1);
128                 if (minSA<i)
129                     l=mid+1,minIndex=minSA;
130                 else
131                     r=mid-1;
132             }
133             if (minIndex!=-1) {
134                 int u=lcp(minIndex,i,n);
135                 if (u) {
136                     k=u;
137                     int l=1,r=rk[i]-1,ret=-1;
138                     while (l<=r) {
139                         int mid=(l+r)>>1;
140                         int curLCP=lcp(sa[mid],i,n);
141                         if (curLCP>=u)
142                             r=mid-1,ret=mid;
143                         else l=mid+1;
144                     }
145                     t=rmq.query(ret,rk[i]-1);
146                 }
147             }
148             l=rk[i]+1;
149             r=n;
150             minIndex=-1;
151             while (l<=r) {
152                 int mid=(l+r)>>1;
153                 int minSA=rmq.query(rk[i]+1,mid);
154                 if (minSA<i)
155                     r=mid-1,minIndex=minSA;
156                 else
157                     l=mid+1;
158             }
159             if (minIndex!=-1) {
160                 int u=lcp(minIndex,i,n);
161                 if (u&&u>=k) {
162                     if (u==k)
163                         t=min(t,minIndex);
164                     else
165                         t=minIndex;
166                     k=u;
167                     int l=rk[i]+1,r=n,ret=-1;
168                     while (l<=r) {
169                         int mid=(l+r)>>1;
170                         int curLCP=lcp(sa[mid],i,n);
171                         if (curLCP>=u)
172                             l=mid+1,ret=mid;
173                         else r=mid-1;
174                     }
175                     t=min(t,rmq.query(rk[i]+1,ret));
176                 }
177             }
178             if (k==-1) {
179                 printf("-1 %d\n",s[i]);
180                 i++;
181             } else {
182                 printf("%d %d\n",k,t);
183                 i+=k;
184             }
185         }
186     }
187 } suf;
188 
189 int main () {
190     int T;
191     scanf("%d",&T);
192     while (T--) {
193         scanf("%s",s);
194         int n=strlen(s);
195         static int cas=1;
196         printf("Case #%d:\n",cas++);
197         suf.solve(n);
198     }
199     return 0;
200 }

 

posted @ 2015-11-24 23:16  活在夢裡  阅读(421)  评论(0编辑  收藏  举报