题意:求A 串中不在 所有B串中出现大不同子串的个数
分析:后缀数组可以很简单的实现求一个串不同字子串的个数,,从这方面下手就很容易想到了,之前比赛的时候,,死活没想法
先将所有串拼接起来,计算不包含分隔符的不同子串的个数sumAB,再单独将所有B串拼接起来,同样的方法求一遍,得到sumB,sumAB-sumB即为所求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <string> int const N= 400100; int wa[N], wb[N], ws[N*2], wv[N]; int rank[N], sa[N], height[N], r[N]; char str[N]; 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* sa, int n, int m ){ int i, j, p, *x= wa, *y= wb, *t; for( i= 0; i< m; ++i ) ws[i]= 0; for( i= 0; i< n; ++i ) ws[ x[i]= r[i] ]++; for( i= 1; i< m; ++i ) ws[i]+= ws[i-1]; for( i= n- 1; i>= 0; i-- ) sa[ --ws[ 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 ) ws[i]= 0; for( i= 0; i< n; ++i ) ws[ wv[i] ]++; for( i= 1; i< m; ++i ) ws[i]+= ws[i-1]; for( i= n- 1; i>= 0; i-- ) sa[ --ws[ wv[i] ] ]= y[i]; t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0; for( i= 1; i< n; ++i ) x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++; } } void callheight( int* r, int*sa, 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 s[N],length[N],id[N]; //s[]表示每一个串的在拼接后在串中的起始下标,length[]表示每一个串的长度,id[]记录拼接后每一个下标对应的原串的id __int64 get_num(int n)//计算不包含分隔符的不同子串的个数 { __int64 sum=0; for(int i=1;i<=n;++i) { if(id[sa[i]]<0) continue; sum+=length[id[sa[i]]]-(sa[i]-s[id[sa[i]]])-height[i]; //拼接后的串的计算子串的方法跟单个串的时候差不多,,原来是一样的,,只不过不能忽视分隔符的存在 } return sum; } void print(int *s,int n) { for(int i=0;i<n;++i) printf("%d ",s[i]); printf("\n"); } int main() { int T,cas=0; int n; scanf("%d",&T); while(T--) { scanf("%d",&n); memset(id,-1,sizeof(id)); int len=-1,m=27; for(int i=0;i<=n;++i) { ++len; scanf("%s",str); length[i]=strlen(str); s[i]=len; for(int j=0;j<length[i];++j) { id[len]=i; r[len++]=str[j]-'a'+1; } r[len]=m++; } r[len]=0; da(r,sa,len+1,m); callheight(r,sa,len); __int64 ans1=get_num(len);//A串 + B 串中所有串可以形成的总的不同子串的个数 for(int i=1;i<=n;++i) s[i]=s[i]-length[0]-1; for(int i=0;i<=len-length[0]-1;++i) { id[i]=id[i+length[0]+1]; r[i]=r[i+length[0]+1]; } len=len-length[0]-1; da(r,sa,len+1,m); callheight(r,sa,len); __int64 ans2=get_num(len);//B中所有串可以形成的总的子串的个数 printf("Case %d: %I64d\n",++cas,ans1-ans2); } return 0; }