1. 程式人生 > >hdu 6194 string string string(後綴數組)

hdu 6194 string string string(後綴數組)

src tin def can clu 如果 子串 bsp con

題目鏈接:hdu 6194 string string string

題意:

給你一個字符串,給你一個k,問你有多少個子串恰好在原串中出現k次。

題解:

後綴數組求出sa後,用height數組的信息去找答案。

每次用k長度的區間去卡height數組,求出該區間的lcp。

該區間的貢獻就是ans=lcp-max(height[i],height[i+k])。

如果ans<=0,就不貢獻。

比如 2 aaa

後綴數組為:

1 a

2 aa

3 aaa

height為 0,1,2

現在掃到[1,2],lcp=1,max(height[i],height[i+k])=2,ans=-1,所以該區間沒有貢獻

到[2,3],lcp=2,max(height[i],height[i+k])=1,ans=1,所以該區間貢獻1。

技術分享
 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 
 5 namespace suffixarray{    
 6     #define FN(n) for(int i=0;i<n;i++)
 7     const int N =1E5+7;
 8     int rnk[N],sa[N],height[N],c[N];char
s[N]; 9 void getsa(int n,int m,int *x=rnk,int *y=height){ 10 FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i]; 11 for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 12 for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){ 13 for(int i=n-k;i<n;i++)y[p++]=i; 14 FN(n)if
(sa[i]>=k)y[p++]=sa[i]-k; 15 FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i]; 16 for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; 17 swap(x,y),p=1,x[sa[0]]=0; 18 for(int i=1;i<n;i++) 19 x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; 20 } 21 FN(n)rnk[sa[i]]=i; 22 for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k) 23 for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++); 24 } 25 } 26 using namespace suffixarray; 27 28 int t,k,n,f[N][20]; 29 30 void rmq(int *a) 31 { 32 for(int i=1;i<=n;i++)f[i][0]=a[i]; 33 for(int j=1;1<<j<n;j++)for(int i=1;i<=n;i++) 34 if(i+(1<<j)-1<=n)f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); 35 else break; 36 } 37 inline int find(int l,int r) 38 { 39 int k=31-__builtin_clz(r-l+1); 40 return min(f[l][k],f[r-(1<<k)+1][k]); 41 } 42 43 int main() 44 { 45 scanf("%d",&t); 46 while(t--) 47 { 48 scanf("%d%s",&k,s); 49 n=strlen(s),getsa(n+1,300); 50 height[n+1]=0;rmq(height); 51 int ans=0; 52 F(i,1,n) 53 { 54 if(i+k-1>n)continue; 55 int lcp; 56 if(i+1>i+k-1)lcp=n-sa[i]; 57 else lcp=find(i+1,i+k-1); 58 lcp-=max(height[i],height[i+k]); 59 if(lcp<=0)continue; 60 ans+=lcp; 61 } 62 printf("%d\n",ans); 63 } 64 return 0; 65 }
View Code

hdu 6194 string string string(後綴數組)