ECNUOJ 2619 询问

询问

Time Limit:2000MS Memory Limit:65536KB
Total Submit:286 Accepted:70

Description 

Pollux最近对字符串匹配很感兴趣,他渐渐发现一个有趣的函数,并且他觉得利用这个函数或许可以建立一种新的匹配算法:
对于字符串S[1…n]和i∈[1 , n] ,定义F(i) 为S 和 S[1…i] 的最长公共后缀的长度.
例如对于串S[1…11] = zaaxbaacbaa ,则F(1) = 0 ,F(2) = 1 , F(3) = 2( 注意S[1…3] = zaa ) ,F(4) = 0 , …… F(10) = 1 ,F(11) = 11 ;
对于串S[1…n],i∈[1 , n] ,S[i…n] 为S的后缀;
但是有一点让他犯难的地方就是他不知道如何快速的计算这个函数在i∈[1 , n]的值,作为ECNU的一名编程高手,你能帮助他解决这个问题吗?

Input 

第一行为一个整数T,表示测数数据的组数.
对于每组数据:
第一行为一个字符串S,只由小写字母组成,如果len(s)表示s的长度,那么1 <= len(s) <= 1000000 ;
接下来一个数N( 1 <= N <= 100000 ),表示询问的次数;
接下来N行,每行一个数x( 1<=x<=len(s))。

Output 

对于每个x输出F(x);

Sample Input 

1
zaaxbaacbaa
11
1
2
3
4
5
6
7
8
9
10
11

Sample Output 

0
1
2
0
0
1
3
0
0
1
11

Source

 

解题:没想到别的什么办法,只好用后缀数组了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 100010;
 4 char s[maxn];
 5 int sa[maxn],t[maxn],t2[maxn];
 6 int height[maxn],rk[maxn],c[maxn],n;
 7 void build_sa(int m) {
 8     int i,*x = t,*y = t2;
 9     for(i = 0; i < m; ++i) c[i] = 0;
10     for(i = 0; i < n; ++i) c[x[i] = s[i]]++;
11     for(i = 1; i < m; ++i) c[i] += c[i-1];
12     for(i = n-1; i >= 0; --i) sa[--c[x[i]]] = i;
13 
14     for(int k = 1; k <= n; k <<= 1) {
15         int p = 0;
16         for(i = n-k; i < n; ++i) y[p++] = i;
17         for(i = 0; i < n; ++i)
18             if(sa[i] >= k) y[p++] = sa[i] - k;
19         for(i = 0; i < m; ++i) c[i] = 0;
20         for(i = 0; i < n; ++i) c[x[y[i]]]++;
21         for(i = 1; i < m; ++i) c[i] += c[i-1];
22         for(i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
23         swap(x,y);
24         x[sa[0]] = 0;
25         for(p = i = 1; i < n; ++i)
26             x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]?p-1:p++;
27         if(p >= n) break;
28         m = p;
29     }
30 }
31 void getHeight() {
32     int i,j,k = 0;
33     for(i = 0; i < n; ++i) rk[sa[i]] = i;
34     for(i = 0; i < n; ++i) {
35         if(k) --k;
36         j = sa[rk[i]-1];
37         while(i + k < n && j + k < n && s[i+k] == s[j+k]) ++k;
38         height[rk[i]] = k;
39     }
40 }
41 int st[maxn][20],m;
42 void initRMQ() {
43     memset(st,0,sizeof st);
44     for(int i = 1; i < n; ++i) st[i][0] = height[i];
45     for(int i = 1; (1<<i) < n; ++i)
46         for(int j = 1; j + (1<<i) <= n; ++j)
47             st[j][i] = min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
48 }
49 int query(int s,int t) {
50     if(s == t) return n - 1 - s;
51     s = rk[s];
52     t = rk[t];
53     if(s > t) swap(s,t);
54     s++;
55     int k = log2(t - s + 1);
56     return min(st[s][k],st[t-(1<<k)+1][k]);
57 }
58 int main() {
59     int kase;
60     scanf("%d",&kase);
61     while(kase--) {
62         scanf("%s",s);
63         n = strlen(s)+1;
64         reverse(s,s+n-1);
65         build_sa(256);
66         getHeight();
67         initRMQ();
68         scanf("%d",&m);
69         while(m--) {
70             int tmp;
71             scanf("%d",&tmp);
72             printf("%d\n",query(0,n - 1 - tmp));
73         }
74     }
75     return 0;
76 }
View Code

 

posted @ 2015-07-08 15:24  狂徒归来  阅读(323)  评论(0编辑  收藏  举报