SPOJ- Distinct Substrings(后缀数组&后缀自动机)
Given a string, we need to find the total number of its distinct substrings.
Input
T- number of test cases. T<=20;
Each test case consists of one string, whose length is <= 1000
Output
For each test case output one number saying the number of distinct substrings.
Example
Sample Input:
2
CCCCC
ABABA
Sample Output:
5
9
Explanation for the testcase with string ABABA:
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.
题解:
本题题意就是给你一个字符串,让你找它有多少不同的子串;
其实就是SAM的板题,只要求每一个状态点的longest[i]-longest[fa[i]]的和就行了。
但由于是后缀数组专题,还是用后缀数组写:
参考代码:
后缀自动机:
#include<bits/stdc++.h> using namespace std; #define PI acos(-1.0) #define mkp make_pair #define pii pair<int,int> #define fi first #define se second #define pb push_back typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=1e5+10; char s[maxn]; struct SAM{ ll ans; int fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26],last,cnt; void Init() { memset(nxt[1],0,sizeof(nxt[1])); last=cnt=1; ans=0; fa[1]=0;l[1]=0; } int NewNode() { ++cnt; memset(nxt[cnt],0,sizeof(nxt[cnt])); fa[cnt]=l[cnt]=0; return cnt; } void Add(int c) { int p=last,np=NewNode(); last=np;l[np]=l[p]+1; while(p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p]; if(!p) fa[np]=1; else { int q=nxt[p][c]; if(l[q]==l[p]+1) fa[np]=q; else { int nq=NewNode(); memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); fa[nq]=fa[q]; l[nq]=l[p]+1; fa[q]=fa[np]=nq; while(nxt[p][c]==q) nxt[p][c]=nq,p=fa[p]; } } ans+=(l[last]-l[fa[last]])*1ll; } void Query() { Init(); for(int i=0,len=strlen(s);i<len;++i) Add(s[i]-'A'); printf("%lld\n",ans); } } sam; int main() { int N; scanf("%d",&N); while(N--) { sam.Init(); scanf("%s",s); sam.Query(); } return 0; }
后缀数组:
#include<iostream> #include<cstdio> #include<cstring> #define rint register int #define ini inline int #define maxn 1000050 using namespace std; char str[maxn]; int y[maxn<<1],x[maxn<<1],c[maxn]; int sa[maxn],rk[maxn],height[maxn]; int n,m,s[maxn]; inline void get_SA() { for(int i=1;i<=m;++i) c[i]=0; for(int i=1;i<=n;++i) ++c[x[i]=s[i]]; for(int i=2;i<=m;++i) c[i]+=c[i-1]; for(int i=n;i>=1;--i) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1) { int num=0; for(int i=n-k+1;i<=n;++i) y[++num]=i; for(int i=1;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k; for(int i=1;i<=m;++i) c[i]=0; for(int i=1;i<=n;++i) ++c[x[i]]; for(int i=2;i<=m;++i) c[i]+=c[i-1]; for(int i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y); x[sa[1]]=1; num=1; for(rint i=2;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num; if(num==n) break; m=num; } } inline void get_height() { int k=0; for(int i=1;i<=n;++i) rk[sa[i]]=i; for(int i=1;i<=n;++i) { if(rk[i]==1) continue;//第一名height为0 if(k) --k;//h[i]>=h[i-1]-1; rint j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) ++k; height[rk[i]]=k;//h[i]=height[rk[i]]; } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",str+1); n=strlen(str+1);m=256; for(int i=1;i<=n;++i) s[i]=str[i]-'A'+1; get_SA(); get_height(); //for(int i=1;i<=n;++i) cout<<sa[i]<<" "<<height[i]<<endl; int ans=0; for(int i=1;i<=n;++i) ans+=n-sa[i]+1-height[i]; printf("%d\n",ans); } return 0; }