SPOJ 694 Distinct Substrings

原创 2012年03月24日 10:16:25

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

题意:给定一个字符串,len<=1000,求不同子串的个数。

思路: 后缀数组。 每个子串一定是某后缀前缀,于是原问题就可以转换为求所有后缀中不同前缀的个数,后缀的排列顺序为字典序排序suffix(sa[1]) < suffix(sa[2] ) < suffix(sa[3])  ....  ,由后缀的排列顺序我们可以得出,由后缀suffix(sa[k]) 产生的新前缀的个数为:len - sa[k] - height[k] ,因为此时suffix(sa[k]) 与 suffix(sa[k-1]) 共有height[k]个前缀是相同的。这样在用O(NlogN)的复杂度求出sa[]数组和 O(N)的复杂度求出height[] 数组之后就可以在O(N)的时间内求出答案。总的复杂度为:O(NlogN)。

代码:

#include<stdio.h>
#include<string.h>
#define MAXN 2010 
char ch[MAXN] ;
int num[MAXN] ;
int T;
int sa[MAXN] , rank[MAXN] ,height[MAXN] ;  
int wa[MAXN] , wb[MAXN] ,wv[MAXN],wd[MAXN] ;   
int N,M;  
int cmp(int *r , int a , int b , int l){  
    return r[a] == r[b] && r[a+l] == r[b+l] ;     
}  
void DA(int *r,int n,int m){        //O(NlogN)  
    int i, j , p , *x=wa, *y=wb,*t ;  
    for( i = 0 ; i < m ; i++ )   wd[i] = 0 ;  
    for( i = 0 ; i < n ; i++ )       wd[x[i]=r[i]] ++ ;  
    for( i = 1 ; i < m ; i++ )       wd[i] += wd[i-1] ;  
    for( i = n-1 ;i >= 0 ; i-- )     sa[--wd[x[i]]] = i ;  
    for( j = 1 , p = 1 ; p < n; j *= 2 , m=p ){  
        for( p = 0 , i = n-j ; i < n ; i++)  y[p++] = i ;  
        for( i = 0 ; i < n ; i++ )   if(sa[i] >= j)   y[p++] = sa[i] - j ;  
        for( i = 0 ; i < n ; i++)    wv[i] = x[y[i]] ;  
        for( i = 0 ; i < m ; i++)    wd[i] = 0 ;  
        for( i = 0 ; i < n ; i++)    wd[wv[i]] ++ ;  
        for( i = 1 ; i < m ; i++)    wd[i] += wd[i-1] ;  
        for( i = n-1 ; i >= 0 ; i--) sa[ --wd[wv[i]]] = y[i] ;  
        for( t = x , x = y , y = t , p = 1 , x[ sa[0] ] = 0,i = 1;i < n ; i++){  
            x[sa[i]] = cmp( y ,sa[i-1] ,sa[i] , j ) ? p-1: p++;   
        }     
    }  
}   
  
void calHeight(int *r , int n){  
    int i , j , k = 0 ;  
    for( i = 1 ; i <= n ; i++)   rank[sa[i]] = i ;  
    for( i = 0 ; i < n ; height[ rank[i++]]=k){  
        for( k ? k-- : 0 , j=sa[rank[i]-1]; r[i+k]==r[j+k] ; k++) ;   
    }     
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%s",ch);	
		int len = strlen(ch);
		for(int i=0;i<len;i++){
			num[i] = ch[i] ;	
		}
		num[len] = 0 ;
		DA(num, len+1 , 300);
		calHeight(num,len);
		int ans = len - sa[1] ;
		for(int i=2;i<=len;i++){
			ans += len - sa[i] - height[i] ;
		}
		printf("%d\n",ans);
	}		
	return 0 ;	
}


相关文章推荐

SPOJ 694 Distinct Substrings(后缀数组 所有不相同子串个数)

题目链接:http://www.spoj.com/problems/DISUBSTR/ 第一次做spoj上的题目 这个题目还是利用height数组,表示后缀数组理解还是靠height数组的理解 这...

spoj694 Distinct Substrings(后缀数组+统计不同子串的个数)

给定一个字符串,求不相同的子串的个数。 算法分析: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相 同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suff...

694. Distinct Substrings SPOJ

//给你长度为n,求不同的字符串个数 //每个子串一定是某个后缀的前缀,那么原问题等价于所求后缀之间不同的前缀个数 #include #include #include using name...

SPOJ 694 DISUBSTR Distinct Substrings 后缀数组

题目大意: 对于给出的字符串(长度不超过1000) 求其不同的子串的个数 大致思路: 就是一个简单的height数组性质的利用,  如果每个子串我们用从位置j开始且长度为k来表示不同的...

spoj694 Distinct Substrings

SPOJ Problem Set (classical)694. Distinct SubstringsProblem code: DISUBSTR Given a string, we need t...
  • hqd_acm
  • hqd_acm
  • 2011年04月13日 20:32
  • 580

spoj694 Distinct Substrings 后缀数组

SPOJ Problem Set (classical) 694. Distinct Substrings Problem code: DISUBSTR

spoj 694. Distinct Substrings(后缀数组)

题意:给出一个串,求串中不同子串的个数。 思路:利用后缀数组的height数组,按照sa[1],sa[2],……,sa[n]顺序计算,第i个串会使答案增加n-sa[i]-height[i]。 题目...
  • qian99
  • qian99
  • 2014年02月12日 14:34
  • 461

Spoj694(Distinct Substrings)求字符串不相同的子串个数(后缀数组)

/********************************************* 题目地址: http://www.spoj.com/problems/DISUBSTR/ 题目大意: 给...
  • Jarily
  • Jarily
  • 2013年03月23日 19:55
  • 1227

spoj694/705 Distinct Substrings - 后缀数组

题目链接:http://acm.hust.edu.cn/vjudge/problem/19282 题目大意:求不同子串的个数 题解:后缀数组.. suffix(i)对子串个数所做的贡献为len-s...

SPOJ 694/705 Distinct Substrings ( 后缀数组 不同子串个数 )

题意 : 求一个字符串中不同子串的
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SPOJ 694 Distinct Substrings
举报原因:
原因补充:

(最多只允许输入30个字)