SPOJ 694 求不同子串数 后缀数组

来源:互联网 发布:腾讯云域名认证 编辑:程序博客网 时间:2024/05/29 19:20

题目链接:http://www.spoj.com/problems/DISUBSTR/

题意:

T个测试数据

每个测试数据一行:字符串,求该字符串有多少个不同的子串。

 

论文思路:

每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相
同的前缀的个数。如果所有的后缀按照suffix(sa[1]), suffix(sa[2]),
suffix(sa[3]), …… ,suffix(sa[n])的顺序计算,不难发现,对于每一次新加
进来的后缀suffix(sa[k]),它将产生n-sa[k]+1 个新的前缀。但是其中有
height[k]个是和前面的字符串的前缀是相同的。所以suffix(sa[k])将“贡献”
出n-sa[k]+1- height[k]个不同的子串。累加后便是原问题的答案。这个做法
的时间复杂度为O(n)。

 

 

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <math.h>#include <set>#define N 100005#define M 105using namespace std;#define rank Rank/** 后缀数组* DC3算法,复杂度O(n)* 所有的相关数组都要开三倍*/const int MAXN=20010;int rank[MAXN],height[MAXN];#define F(x) ((x)/3+((x)%3==1?0:tb))#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3];int c0(int *r,int a,int b){return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];}int c12(int k,int *r,int a,int b){if(k == 2)return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );}void sort(int *r,int *a,int *b,int n,int m){int i;for(i = 0;i < n;i++)wv[i] = r[a[i]];for(i = 0;i < m;i++)wss[i] = 0;for(i = 0;i < n;i++)wss[wv[i]]++;for(i = 1;i < m;i++)wss[i] += wss[i-1];for(i = n-1;i >= 0;i--)b[--wss[wv[i]]] = a[i];}void dc3(int *r,int *sa,int n,int m){int i, j, *rn = r + n;int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;r[n] = r[n+1] = 0;for(i = 0;i < n;i++)if(i %3 != 0)wa[tbc++] = i;sort(r + 2, wa, wb, tbc, m);sort(r + 1, wb, wa, tbc, m);sort(r, wa, wb, tbc, m);for(p = 1, rn[F(wb[0])] = 0, i = 1;i < tbc;i++)rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;if(p < tbc)dc3(rn,san,tbc,p);else for(i = 0;i < tbc;i++)san[rn[i]] = i;for(i = 0;i < tbc;i++) if(san[i] < tb)wb[ta++] = san[i] * 3;if(n % 3 == 1)wb[ta++] = n - 1;sort(r, wb, wa, ta, m);for(i = 0;i < tbc;i++)wv[wb[i] = G(san[i])] = i;for(i = 0, j = 0, p = 0;i < ta && j < tbc;p++)sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];for(;i < ta;p++)sa[p] = wa[i++];for(;j < tbc;p++)sa[p] = wb[j++];}//str和sa也要三倍void da(int str[],int sa[],int rank[],int height[],int n,int m){for(int i = n;i < n*3;i++)str[i] = 0;dc3(str, sa, n+1, m);int i,j,k = 0;for(i = 0;i <= n;i++)rank[sa[i]] = i;for(i = 0;i < n; i++){if(k) k--;j = sa[rank[i]-1];while(str[i+k] == str[j+k]) k++;height[rank[i]] = k;}}char str[MAXN];int r[MAXN];int sa[MAXN];int main(){int T, i, j;scanf("%d",&T);while(T--){scanf("%s",str);int len = strlen(str); str[len] = 0;for(i = 0; i <= len; i++)r[i] = str[i];da(r, sa, rank, height, len, 128);int ans = 0;for(i = 1; i <= len; i++)ans += len - sa[i] - height[i];printf("%d\n", ans);}return 0;}/*99CCCCCABABA*/


 

0 0
原创粉丝点击