SPOJ 705 New Distinct Substrings

New Distinct Substrings

Time Limit: 2000ms
Memory Limit: 262144KB
This problem will be judged on SPOJ. Original ID: SUBST1
64-bit integer IO format: %lld      Java class name: Main
 

Given a string, we need to find the total number of its distinct substrings.

Input

T- number of test cases. T<=20; Each test case consists of one string, whose length is <= 50000

Output

For each test case output one number saying the number of distinct substrings.

Example

Input:
2
CCCCC
ABABA

Output:
5
9

Source

 
解题:求不同子串的个数。后缀数组lcp的应用。
 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <climits>
 7 #include <vector>
 8 #include <queue>
 9 #include <cstdlib>
10 #include <string>
11 #include <set>
12 #include <stack>
13 #define LL long long
14 #define pii pair<int,int>
15 #define INF 0x3f3f3f3f
16 using namespace std;
17 const int maxn = 50010;
18 int rk[maxn],wb[maxn],wv[maxn],wd[maxn],lcp[maxn];
19 bool cmp(int *r,int i,int j,int k){
20     return r[i] == r[j] && r[i+k] == r[j+k];
21 }
22 void da(int *r,int *sa,int n,int m){
23     int i,k,p,*x = rk,*y = wb;
24     for(i = 0; i < m; ++i) wd[i] = 0;
25     for(i = 0; i < n; ++i) wd[x[i] = r[i]]++;
26     for(i = 1; i < m; ++i) wd[i] += wd[i-1];
27     for(i = n-1; i >= 0; --i) sa[--wd[x[i]]] = i;
28 
29     for(p = k = 1; p < n; k <<= 1,m = p){
30         for(p = 0,i = n-k; i < n; ++i) y[p++] = i;
31         for(i = 0; i < n; ++i) if(sa[i] >= k) y[p++] = sa[i] - k;
32         for(i = 0; i < n; ++i) wv[i] = x[y[i]];
33 
34         for(i = 0; i < m; ++i) wd[i] = 0;
35         for(i = 0; i < n; ++i) wd[wv[i]]++;
36         for(i = 1; i < m; ++i) wd[i] += wd[i-1];
37         for(i = n-1; i >= 0; --i) sa[--wd[wv[i]]] = y[i];
38 
39         swap(x,y);
40         x[sa[0]] = 0;
41         for(p = i = 1; i < n; ++i)
42             x[sa[i]] = cmp(y,sa[i-1],sa[i],k)?p-1:p++;
43     }
44 }
45 void calcp(int *r,int *sa,int n){
46     for(int i = 1; i <= n; ++i) rk[sa[i]] = i;
47     int h = 0;
48     for(int i = 0; i < n; ++i){
49         if(h > 0) h--;
50         for(int j = sa[rk[i]-1]; i+h < n && j+h < n; h++)
51             if(r[i+h] != r[j+h]) break;
52         lcp[rk[i]-1] = h;
53     }
54 }
55 int r[maxn],sa[maxn];
56 char str[maxn];
57 int main() {
58     int n;
59     scanf("%d",&n);
60     while(n--){
61         scanf("%s",str);
62         int len = strlen(str);
63         for(int i = 0; i < len; ++i)
64             r[i] = str[i];
65         r[len] = 0;
66         da(r,sa,len+1,128);
67         calcp(r,sa,len);
68         int ans = 0;
69         for(int i = 1; i <= len; ++i)
70             ans += len - sa[i] - lcp[i];
71         printf("%d
",ans);
72     }
73     return 0;
74 }
View Code

后缀自动机

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 100010;
 4 char str[maxn];
 5 int ret,n;
 6 struct SAM{
 7     struct node{
 8         int son[26],f,len;
 9         void init(){
10             f = -1;
11             len = 0;
12             memset(son,-1,sizeof son);
13         }
14     }e[maxn];
15     int tot,last;
16     int newnode(int len = 0){
17         e[tot].init();
18         e[tot].len = len;
19         return tot++;
20     }
21     void init(){
22         tot = last = 0;
23         newnode();
24     }
25     void extend(int c){
26         int p = last,np = newnode(e[p].len + 1);
27         while(p != -1 && e[p].son[c] == -1){
28             e[p].son[c] = np;
29             p = e[p].f;
30         }
31         if(p == -1) e[np].f = 0;
32         else{
33             int q = e[p].son[c];
34             if(e[p].len + 1 == e[q].len) e[np].f = q;
35             else{
36                 int nq = newnode();
37                 e[nq] = e[q];
38                 e[nq].len = e[p].len + 1;
39                 e[q].f = e[np].f = nq;
40                 while(p != -1 && e[p].son[c] == q){
41                     e[p].son[c] = nq;
42                     p = e[p].f;
43                 }
44             }
45         }
46         last = np;
47     }
48     void solve(){
49         ret = 0;
50         for(int i = 1; i < tot; ++i)
51             ret += e[i].len - e[e[i].f].len;
52         printf("%d
",ret);
53     }
54 }sam;
55 
56 int main(){
57     int kase;
58     scanf("%d",&kase);
59     while(kase--){
60         scanf("%s",str);
61         n = strlen(str);
62         sam.init();
63         for(int i = ret = 0; str[i]; ++i)
64             sam.extend(str[i]-'A');
65         sam.solve();
66     }
67     return 0;
68 }
View Code
原文地址:https://www.cnblogs.com/crackpotisback/p/4033744.html