题意:
给你一个字符串,让你找不重叠且出现大于1次以上的字串个数
题解:
后缀数组height数组的应用,我们枚举字串的长度,然后将height数组分段,符合条件就ans++
为什么要这样做,因为height数组存的是相邻排名后缀的最大前缀数,如果height的值大于等于我们枚举的长度len,
那么有可能这一段存在有两个以上的该长度的字串,然后我们统计这个段的开头长度l和结束长度r,如果r-l>=len,说明这段必有
大于一个以上的该长度的相同子串,因为我们每次都是枚举len,按len分的段,所以不会重复。
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 =1E3+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 27 inline void upd(int &a,int b){if(a>b)a=b;} 28 inline void upu(int &a,int b){if(a<b)a=b;} 29 30 using namespace suffixarray; 31 int main(){ 32 while(~scanf("%s",s)) 33 { 34 if(s[0]==‘#‘)break; 35 int len=strlen(s),ans=0; 36 getsa(len+1,128); 37 F(i,1,len) 38 { 39 int l=len+1,r=0; 40 F(j,1,len) 41 { 42 if(height[j]>=i)upd(l,sa[j]),upu(r,sa[j]); 43 else 44 { 45 if(r-l>=i)ans++; 46 l=r=sa[j]; 47 } 48 } 49 if(r-l>=i)ans++; 50 } 51 printf("%d\n",ans); 52 } 53 return 0; 54 }
时间: 2024-08-03 16:34:01