wenbao与后缀数组

倍增算法(da)

 1 #define maxn 1000001
 2 int wa[maxn],wb[maxn],wv[maxn],wss[maxn];
 3
 4 int cmp(int *r, int a, int b, int l) {
 5     return r[a] == r[b] && r[a+l] == r[b+l];
 6 }
 7
 8 void da(int *r, int *sa, int n, int m) {
 9     int i, j, p, *x = wa, *y = wb, *t;
10     for(i = 0; i < m; i++) wss[i] = 0;
11     for(i = 0; i < n; i++) wss[x[i]=r[i]]++;
12     for(i = 1; i < m; i++) wss[i] += wss[i-1];
13     for(i = n-1; i >= 0; i--) sa[--wss[x[i]]] = i;
14     for(j = 1, p = 1; p < n; j *= 2, m = p) {
15         for(p = 0, i = n-j; i < n; i++) y[p++] = i;
16         for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
17         for(i = 0; i < n; i++) wv[i] = x[y[i]];
18         for(i = 0; i < m; i++) wss[i] = 0;
19         for(i = 0; i < n; i++) wss[wv[i]] ++;
20         for(i = 1; i < m; i++) wss[i] += wss[i-1];
21         for(i = n-1; i>=0; i--) sa[--wss[wv[i]]] = y[i];
22         for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
23             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
24     }
25     return;
26 }
27
28 int rank[maxn], height[maxn];
29 void calheight(int *r, int *sa, int n) {
30     int i, j, k = 0;
31     for(i = 1; i <= n; i++) rank[sa[i]] = i;
32     for(i = 0; i < n; height[rank[i++]] = k)
33         for(k ? k-- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
34     return;
35 }
36
37 int RMQ[maxn];
38 int mm[maxn];
39 int best[20][maxn];
40 void initRMQ(int n) {
41     int i, j, a, b;
42     for(mm[0] =- 1, i = 1; i <= n; i++)
43         mm[i] = ((i&(i-1)) == 0) ? mm[i-1]+1 : mm[i-1];
44     for(i = 1; i <= n; i++) best[0][i] = i;
45     for(i = 1; i <= mm[n]; i++)
46         for(j = 1; j <= n+1-(1<<i); j++) {
47             a = best[i-1][j];
48             b = best[i-1][j+(1<<(i-1))];
49             if(RMQ[a] < RMQ[b]) best[i][j] = a;
50             else best[i][j] = b;
51         }
52     return;
53 }
54
55 int askRMQ(int a, int b) {
56     int t;
57     t = mm[b-a+1];
58     b -= (1<<t)-1;
59     a = best[t][a];
60     b = best[t][b];
61     return RMQ[a] < RMQ[b] ? a : b;
62 }
63 int lcp(int a, int b) {
64     int t;
65     a = rank[a];
66     b = rank[b];
67     if(a > b)  t = a, a = b, b = t;
68     return(height[askRMQ(a+1, b)]);
69 }
70
71 int sa[maxn], r[maxn];

DC3

 1 #define maxn 1000009
 2 #define F(x) ((x)/3+((x)%3 == 1?0:tb))
 3 #define G(x) ((x)<tb ? (x)*3+1 : ((x)-tb)*3+2)
 4
 5 int wa[maxn], wb[maxn], wv[maxn], wss[maxn];
 6 int c0(int *r, int a, int b) {
 7     return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
 8 }
 9 int c12(int k, int *r, int a, int b) {
10     if(k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a+1, b+1);
11     else return r[a] < r[b] || r[a] == r[b] && wv[a+1] < wv[b+1];
12 }
13
14 void sort(int *r, int *a, int *b, int n, int m) {
15     int i;
16     for(i = 0; i < n; i++) wv[i] = r[a[i]];
17     for(i = 0; i < m; i++) wss[i] = 0;
18     for(i = 0; i < n; i++) wss[wv[i]] ++;
19     for(i = 1; i < m; i++) wss[i] += wss[i-1];
20     for(i = n-1; i >= 0; i--) b[--wss[wv[i]]] = a[i];
21     return;
22 }
23
24 void dc3(int *r, int *sa, int n, int m) {
25     int i, j, *rn = r+n, *san = sa+n, ta = 0, tb = (n+1)/3, tbc=0, p;
26     r[n] = r[n+1] = 0;
27     for(i = 0; i < n; i++) if(i%3 != 0) wa[tbc++] = i;
28     sort(r+2, wa, wb, tbc, m);
29     sort(r+1, wb, wa, tbc, m);
30     sort(r, wa, wb, tbc, m);
31     for(p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
32         rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
33     if(p < tbc) dc3(rn, san, tbc, p);
34     else for(i = 0; i < tbc; i++) san[rn[i]] = i;
35     for(i = 0; i < tbc; i++) if(san[i] < tb) wb[ta++] = san[i]*3;
36     if(n%3 == 1) wb[ta++] = n-1;
37     sort(r, wb, wa, ta, m);
38     for(i = 0; i < tbc; i++) wv[wb[i]=G(san[i])] = i;
39     for(i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
40         sa[p] = c12(wb[j]%3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
41     for(; i < ta; p++) sa[p] = wa[i++];
42     for(; j < tbc; p++) sa[p] = wb[j++];
43     return;
44 }
45
46 int rank[maxn*3], height[maxn*3];
47 void calheight(int *r, int *sa, int n) {
48     int i, j, k = 0;
49     for(i = 1; i <= n; i++) rank[sa[i]] = i;
50     for(i = 0; i < n; height[rank[i++]] = k)
51         for(k ? k-- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
52     return;
53 }
54
55 int RMQ[maxn];
56 int mm[maxn];
57 int best[20][maxn];
58 void initRMQ(int n) {
59     int i, j, a, b;
60     for(mm[0] =- 1, i = 1; i <= n; i++)
61         mm[i] = ((i & (i-1)) == 0) ? mm[i-1]+1 : mm[i-1];
62     for(i = 1; i <= n; i++) best[0][i] = i;
63     for(i = 1; i <= mm[n]; i++)
64         for(j = 1; j <= n+1-(1<<i); j++) {
65             a = best[i-1][j];
66             b = best[i-1][j+(1<<(i-1))];
67             if(RMQ[a] < RMQ[b]) best[i][j] = a;
68             else best[i][j] = b;
69         }
70     return;
71 }
72
73 int askRMQ(int a, int b) {
74     int t;
75     t = mm[b-a+1];
76     b -= (1<<t)-1;
77     a = best[t][a];
78     b = best[t][b];
79     return RMQ[a] < RMQ[b] ? a : b;
80 }
81
82 int lcp(int a, int b) {
83     int t;
84     a = rank[a];
85     b = rank[b];
86     if(a > b) t = a, a = b, b = t;
87     return(height[askRMQ(a+1, b)]);
88 }
89
90 int sa[maxn*3], r[maxn];

-------------------------------------------------------

http://www.spoj.com/problems/DISUBSTR/

spoj 694

求不同子串的个数

 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;
 4
 5 const int maxn = 1009;
 6 int a[maxn], sa[maxn], len;
 7 char str[maxn];
 8
 9 int wa[maxn], wb[maxn], wv[maxn], wws[maxn];
10 int cmp(int *r, int a, int b, int l){
11     return r[a] == r[b] && r[a+l] == r[b+l];
12 }
13 //sa from 0 -> n-1
14 void da(int *r, int *sa, int n, int m){
15     int i, j, p, *x = wa, *y = wb, *t;
16     for(i = 0; i < m; i++) wws[i] = 0;
17     for(i = 0; i < n; i++) wws[x[i] = r[i]]++;
18     for(i = 1; i < m; i++) wws[i] += wws[i-1];
19     for(i = n-1; i >= 0; i--) sa[--wws[x[i]]] = i;
20     for(j = 1,p = 1; p < n; j *= 2, m = p){
21         for(p = 0,i = n-j; i<n;i++) y[p++] = i;
22         for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
23         for(i = 0; i < n; i++) wv[i] = x[y[i]];
24         for(i = 0; i < m; i++) wws[i] = 0;
25         for(i = 0; i < n; i++) wws[wv[i]] ++;
26         for(i = 1; i < m; i++) wws[i] += wws[i-1];
27         for(i = n-1; i >= 0; i--) sa[--wws[wv[i]]] = y[i];
28         for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
29             x[sa[i]] = cmp(y,sa[i-1], sa[i],j) ? p-1 : p++;
30     }
31     return ;
32 }
33
34 int Rank[maxn], height[maxn];
35 void calheight(int *r, int *sa, int n){
36     int i, j, k = 0;
37     for(i = 1; i <= n; i++) Rank[sa[i]] = i;
38     for(i = 0; i < n; height[Rank[i++]] = k)
39         for(k ? k-- : 0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k++);
40     return;
41 }
42
43
44 int main(){
45     int t;
46     scanf("%d", &t);
47     while(t--){
48         scanf("%s", str);
49         int len = strlen(str);
50         for(int i = 0; i < len; ++i) a[i] = str[i];
51         a[len] = 1;
52         da(a, sa, len+1, 555);
53         calheight(a, sa, len);
54         int sum = 0;
55         for(int i = 1; i <= len; ++i){
56             sum = sum + len-sa[i]-height[i];
57         }
58         printf("%d\n", sum);
59     }
60     return 0;
61 }

--------------------------------------------------------

到今天才是1/8的男人

http://poj.org/problem?id=1743(楼教主的男人八题之一)

求不重叠的最长公共串

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 using namespace std;
 5
 6 const int maxn = 20009;
 7 int a[maxn], sa[maxn], len;
 8 char str[maxn];
 9
10 int wa[maxn], wb[maxn], wv[maxn], wws[maxn];
11 int cmp(int *r, int a, int b, int l){
12     return r[a] == r[b] && r[a+l] == r[b+l];
13 }
14 //sa from 0 -> n-1
15 void da(int *r, int *sa, int n, int m){
16     int i, j, p, *x = wa, *y = wb, *t;
17     for(i = 0; i < m; i++) wws[i] = 0;
18     for(i = 0; i < n; i++) wws[x[i] = r[i]]++;
19     for(i = 1; i < m; i++) wws[i] += wws[i-1];
20     for(i = n-1; i >= 0; i--) sa[--wws[x[i]]] = i;
21     for(j = 1,p = 1; p < n; j *= 2, m = p){
22         for(p = 0,i = n-j; i<n;i++) y[p++] = i;
23         for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
24         for(i = 0; i < n; i++) wv[i] = x[y[i]];
25         for(i = 0; i < m; i++) wws[i] = 0;
26         for(i = 0; i < n; i++) wws[wv[i]] ++;
27         for(i = 1; i < m; i++) wws[i] += wws[i-1];
28         for(i = n-1; i >= 0; i--) sa[--wws[wv[i]]] = y[i];
29         for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
30             x[sa[i]] = cmp(y,sa[i-1], sa[i],j) ? p-1 : p++;
31     }
32     return ;
33 }
34
35 int Rank[maxn], height[maxn];
36 void calheight(int *r, int *sa, int n){
37     int i, j, k = 0;
38     for(i = 1; i <= n; i++) Rank[sa[i]] = i;
39     for(i = 0; i < n; height[Rank[i++]] = k)
40         for(k ? k-- : 0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k++);
41     return;
42 }
43
44 bool ok(int x, int len){
45     int mi = sa[1], ma = sa[1];
46     for(int i = 2; i <= len; ++i){
47         if(height[i] < x) mi = ma = sa[i];
48         else{
49             if(sa[i] < mi) mi = sa[i];
50             if(sa[i] > ma) ma = sa[i];
51             //不能 ma-mi >= x,同样a映射的是差值若相等必重叠
52             if(ma - mi > x) return true;
53         }
54     }
55     return false;
56 }
57
58 int main(){
59     int n, x, y;
60     while(~scanf("%d", &n) && n){
61         //n个数,a[i] 存储a[i+1]-a[i]的值 a的范围是 0 -> n-1
62         scanf("%d", &x);
63         for(int i = 0; i < n-1; ++i) scanf("%d", &y), a[i] = y-x+99, x = y;
64         a[n-1] = 0, n--;
65         da(a, sa, n+1, 555);
66         calheight(a, sa, n);
67         int l = 0, r = n, t = 0;
68         while(l <= r){
69             int mid = (l+r)>>1;
70             if(ok(mid, n)) t = mid, l = mid+1;
71             else r = mid-1;
72         }
73         //因为a为实际数组的差值,所以用四来判断
74         printf("%d\n", t >= 4 ? t+1 : 0);
75     }
76     return 0;
77 }

--------------------------------------------------------

uva11107

输入n个DNA序列,求出长度最大的字符串,使得它在超过一半的DNA序列中连续出现,若有多解按照字典序从小到大输出

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5
  6 const int maxn = 1001 * 100 + 10;
  7
  8 struct SuffixArray {
  9   int s[maxn];      // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)
 10   int sa[maxn];     // 后缀数组
 11   int rank[maxn];   // 名次数组. rank[0]一定是n-1,即最后一个字符
 12   int height[maxn]; // height数组
 13   int t[maxn], t2[maxn], c[maxn]; // 辅助数组
 14   int n; // 字符个数
 15
 16   void clear() { n = 0; memset(sa, 0, sizeof(sa)); }
 17
 18   // m为最大字符值加1。调用之前需设置好s和n
 19   void build_sa(int m) {
 20     int i, *x = t, *y = t2;
 21     for(i = 0; i < m; i++) c[i] = 0;
 22     for(i = 0; i < n; i++) c[x[i] = s[i]]++;
 23     for(i = 1; i < m; i++) c[i] += c[i-1];
 24     for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
 25     for(int k = 1; k <= n; k <<= 1) {
 26       int p = 0;
 27       for(i = n-k; i < n; i++) y[p++] = i;
 28       for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;
 29       for(i = 0; i < m; i++) c[i] = 0;
 30       for(i = 0; i < n; i++) c[x[y[i]]]++;
 31       for(i = 0; i < m; i++) c[i] += c[i-1];
 32       for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
 33       swap(x, y);
 34       p = 1; x[sa[0]] = 0;
 35       for(i = 1; i < n; i++)
 36         x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;
 37       if(p >= n) break;
 38       m = p;
 39     }
 40   }
 41
 42   void build_height() {
 43     int i, j, k = 0;
 44     for(i = 0; i < n; i++) rank[sa[i]] = i;
 45     for(i = 0; i < n; i++) {
 46       if(k) k--;
 47       int j = sa[rank[i]-1];
 48       while(s[i+k] == s[j+k]) k++;
 49       height[rank[i]] = k;
 50     }
 51   }
 52 };
 53
 54 const int maxc = 100 + 10; // 串的个数
 55 const int maxl = 1000 + 10; // 每个串的长度
 56
 57 SuffixArray sa;
 58 int n;
 59 char word[maxl];
 60 int idx[maxn];
 61 int flag[maxc];
 62
 63 // 子串[L,R) 是否符合要求
 64 bool good(int L, int R) {
 65   memset(flag, 0, sizeof(flag));
 66   if(R - L <= n/2) return false;
 67   int cnt = 0;
 68   for(int i = L; i < R; i++) {
 69     int x = idx[sa.sa[i]];
 70     if(x != n && !flag[x]) { flag[x] = 1; cnt++; }
 71   }
 72   return cnt > n/2;
 73 }
 74
 75 void print_sub(int L, int R) {
 76   for(int i = L; i < R; i++)
 77     printf("%c", sa.s[i] - 1 + ‘a‘);
 78   printf("\n");
 79 }
 80
 81 bool print_solutions(int len, bool print) {
 82   int L = 0;
 83   for(int R = 1; R <= sa.n; R++) {
 84     if(R == sa.n || sa.height[R] < len) { // 新开一段
 85       if(good(L, R)) {
 86         if(print) print_sub(sa.sa[L], sa.sa[L] + len); else return true;
 87       }
 88       L = R;
 89     }
 90   }
 91   return false;
 92 }
 93
 94 void solve(int maxlen) {
 95   if(!print_solutions(1, false))
 96     printf("?\n");
 97   else {
 98     int L = 1, R = maxlen, M;
 99     while(L < R) {
100       M = L + (R-L+1)/2;
101       if(print_solutions(M, false)) L = M;
102       else R = M-1;
103     }
104     print_solutions(L, true);
105   }
106 }
107
108 // 给字符串加上一个字符,属于字符串i
109 void add(int ch, int i) {
110   idx[sa.n] = i;
111   sa.s[sa.n++] = ch;
112 }
113
114 int main() {
115   int kase = 0;
116   while(scanf("%d", &n) == 1 && n) {
117     if(kase++ > 0) printf("\n");
118     int maxlen = 0;
119     sa.clear();
120     for(int i = 0; i < n; i++) {
121       scanf("%s", word);
122       int sz = strlen(word);
123       maxlen = max(maxlen, sz);
124       for(int j = 0; j < sz; j++)
125         add(word[j] - ‘a‘ + 1, i);
126       add(100 + i, n); // 结束字符
127     }
128     add(0, n);
129
130     if(n == 1) printf("%s\n", word);
131     else {
132       sa.build_sa(100 + n);
133       sa.build_height();
134       solve(maxlen);
135     }
136   }
137   return 0;
138 }

----------------------------------------------------------------

http://acm.timus.ru/problem.aspx?space=1&num=1297

求最长回文串(当然可以用o(n)的算法实现)

 1 #include <stdio.h>
 2 #include <string.h>
 3 #define maxn 2002
 4
 5 int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
 6
 7 int cmp(int *r,int a,int b,int l){
 8     return r[a]==r[b]&&r[a+l]==r[b+l];
 9 }
10
11 void da(int *r,int *sa,int n,int m){
12     int i,j,p,*x=wa,*y=wb,*t;
13     for(i=0;i<m;i++) ws[i]=0;
14     for(i=0;i<n;i++) ws[x[i]=r[i]]++;
15     for(i=1;i<m;i++) ws[i]+=ws[i-1];
16     for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
17     for(j=1,p=1;p<n;j*=2,m=p){
18         for(p=0,i=n-j;i<n;i++) y[p++]=i;
19         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
20         for(i=0;i<n;i++) wv[i]=x[y[i]];
21         for(i=0;i<m;i++) ws[i]=0;
22         for(i=0;i<n;i++) ws[wv[i]]++;
23         for(i=1;i<m;i++) ws[i]+=ws[i-1];
24         for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
25         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
26             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
27     }
28     return;
29 }
30
31 int rank[maxn],height[maxn];
32 void calheight(int *r,int *sa,int n){
33     int i,j,k=0;
34     for(i=1;i<=n;i++) rank[sa[i]]=i;
35     for(i=0;i<n;height[rank[i++]]=k)
36         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
37     return;
38 }
39
40 int RMQ[maxn];
41 int mm[maxn];
42 int best[20][maxn];
43 void initRMQ(int n){
44     int i,j,a,b;
45     for(mm[0]=-1,i=1;i<=n;i++)
46         mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
47     for(i=1;i<=n;i++) best[0][i]=i;
48     for(i=1;i<=mm[n];i++)
49         for(j=1;j<=n+1-(1<<i);j++){
50             a=best[i-1][j];
51             b=best[i-1][j+(1<<(i-1))];
52             if(RMQ[a]<RMQ[b]) best[i][j]=a;
53             else best[i][j]=b;
54         }
55     return;
56 }
57
58 int askRMQ(int a,int b){
59     int t;
60     t=mm[b-a+1];b-=(1<<t)-1;
61     a=best[t][a];b=best[t][b];
62     return RMQ[a]<RMQ[b]?a:b;
63 }
64
65 int lcp(int a,int b){
66     int t;
67     a=rank[a];b=rank[b];
68     if(a>b) {t=a;a=b;b=t;}
69     return(height[askRMQ(a+1,b)]);
70 }
71
72 char st[maxn];
73 int r[maxn],sa[maxn];
74
75 int main(){
76     int i,n,len,k,ans=0,w;
77     scanf("%s",st);
78     len=strlen(st);
79     for(i=0;i<len;i++) r[i]=st[i];
80     r[len]=1;
81     for(i=0;i<len;i++) r[i+len+1]=st[len-1-i];
82     n=len+len+1;
83     r[n]=0;
84     da(r,sa,n+1,128);
85     calheight(r,sa,n);
86     for(i=1;i<=n;i++) RMQ[i]=height[i];
87     initRMQ(n);
88     for(i=0;i<len;i++){
89         k=lcp(i,n-i);
90         if(k*2>ans) ans=k*2,w=i-k;
91         k=lcp(i,n-i-1);
92         if(k*2-1>ans) ans=k*2-1,w=i-k+1;
93     }
94     st[w+ans]=0;
95     printf("%s\n",st+w);
96     return 0;
97 }

----------------------------------------------------------------

http://poj.org/problem?id=2406

求字符串的最长循环节(KMP裸题),这里看后缀数组解法

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5
 6 #define maxn 1000010
 7 #define F(x) ((x)/3+((x)%3 == 1?0:tb))
 8 #define G(x) ((x)<tb ? (x)*3+1 : ((x)-tb)*3+2)
 9
10 int wa[maxn], wb[maxn], wv[maxn], wss[maxn];
11 int c0(int *r, int a, int b) {
12     return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
13 }
14 int c12(int k, int *r, int a, int b) {
15     if(k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a+1, b+1);
16     else return r[a] < r[b] || r[a] == r[b] && wv[a+1] < wv[b+1];
17 }
18
19 void sort(int *r, int *a, int *b, int n, int m) {
20     int i;
21     for(i = 0; i < n; i++) wv[i] = r[a[i]];
22     for(i = 0; i < m; i++) wss[i] = 0;
23     for(i = 0; i < n; i++) wss[wv[i]] ++;
24     for(i = 1; i < m; i++) wss[i] += wss[i-1];
25     for(i = n-1; i >= 0; i--) b[--wss[wv[i]]] = a[i];
26     return;
27 }
28
29 void dc3(int *r, int *sa, int n, int m) {
30     int i, j, *rn = r+n, *san = sa+n, ta = 0, tb = (n+1)/3, tbc=0, p;
31     r[n] = r[n+1] = 0;
32     for(i = 0; i < n; i++) if(i%3 != 0) wa[tbc++] = i;
33     sort(r+2, wa, wb, tbc, m);
34     sort(r+1, wb, wa, tbc, m);
35     sort(r, wa, wb, tbc, m);
36     for(p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
37         rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
38     if(p < tbc) dc3(rn, san, tbc, p);
39     else for(i = 0; i < tbc; i++) san[rn[i]] = i;
40     for(i = 0; i < tbc; i++) if(san[i] < tb) wb[ta++] = san[i]*3;
41     if(n%3 == 1) wb[ta++] = n-1;
42     sort(r, wb, wa, ta, m);
43     for(i = 0; i < tbc; i++) wv[wb[i]=G(san[i])] = i;
44     for(i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
45         sa[p] = c12(wb[j]%3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
46     for(; i < ta; p++) sa[p] = wa[i++];
47     for(; j < tbc; p++) sa[p] = wb[j++];
48     return;
49 }
50
51 int rk[3*maxn], height[3*maxn];
52 void calheight(int *r, int *sa, int n) {
53     int i, j, k = 0;
54     for(i = 1; i <= n; i++) rk[sa[i]] = i;
55     for(i = 0; i < n; height[rk[i++]] = k)
56         for(k ? k-- : 0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k++);
57     return;
58 }
59
60 char str[maxn];
61 int r[maxn], num[maxn], sa[3*maxn];
62
63 int main(){
64     while(scanf("%s", str) && str[0] != ‘.‘){
65         int len = strlen(str);
66         for(int i = 0; i < len; ++i){
67             r[i] = str[i]-‘a‘+2;
68         }
69         r[len] = 1;
70         dc3(r, sa, len+1, 30);
71         calheight(r, sa, len);
72         int x = rk[0], ma = maxn;
73         num[x] = len;
74         for(int i = x-1; i >= 0; --i){
75             num[i] = min(ma, height[i+1]);
76             //cout<<"^^^"<<endl;
77         }
78         ma = maxn;
79         for(int i = x+1; i <= len; ++i){
80             num[i] = min(ma, height[i]);
81         }
82         int k = 1;
83         for(int i = 1; i <= len; ++i){
84             //cout << i << "&&" << num[i] << endl;
85             if(len%i == 0 && num[rk[i]] == len-i){
86                 printf("%d\n", len/i);
87                 break;
88             }
89         }
90     }
91 }

----------------------------------------------------------------

----------------------------------------------------------------

----------------------------------------------------------------

----------------------------------------------------------------

----------------------------------------------------------------

只有不断学习才能进步!

原文地址:https://www.cnblogs.com/wenbao/p/7401180.html

时间: 2024-10-09 00:44:17

wenbao与后缀数组的相关文章

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【tyvj1860】后缀数组

描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0你的任务就是求出SA和height这两个数组.字符串长度<=200000 输入格式 一行,为描述中的字符串(仅会出现小写

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>