SPOJ DISUBSTR ——后缀数组
【题目分析】
后缀数组模板题。
由于height数组存在RMQ的性质。
那么对于一个后缀,与前面相同的串总共有h[i]+sa[i]个。然后求和即可。
【代码】(模板来自Claris,这个板子太漂亮了)
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define maxn 500005 #define N 500005 #define inf 0x3f3f3f3f #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) void Finout() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif } int Getint() { int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } struct Suffix_Array{ char s[maxn]; int rk[maxn],sa[maxn],h[maxn],tmp[maxn],cnt[maxn]; void build(int n,int m) { int i,j,k;n++; F(i,0,2*5+4) rk[i]=sa[i]=h[i]=tmp[i]=0; F(i,0,m-1) cnt[i]=0; F(i,0,n-1) cnt[rk[i]=s[i]]++; F(i,1,m-1) cnt[i]+=cnt[i-1]; F(i,0,n-1) sa[--cnt[rk[i]]]=i; for (k=1;k<=n;k<<=1) { F(i,0,n-1) { j=sa[i]-k; if (j<0) j+=n; tmp[cnt[rk[j]]++]=j; } sa[tmp[cnt[0]=0]]=j=0; F(i,1,n-1) { if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i; sa[tmp[i]]=j; } memcpy(rk,sa,n*sizeof(int)); memcpy(sa,tmp,n*sizeof(int)); if (j>=n-1) break; } for (j=rk[h[i=k=0]=0];i<n-1;++i,++k) while (~k&&s[i]!=s[sa[j-1]+k]) h[j]=k--,j=rk[sa[j]+1]; } }arr; int main() { int tt; scanf("%d",&tt); while (tt--) { scanf("%s",arr.s); int ans=0,l=strlen(arr.s); arr.s[l]=0; arr.build(l,128); ans+=l-arr.sa[1]; F(i,2,l) ans+=l-arr.sa[i]-arr.h[i]; cout<<ans<<endl; } }
UPD(2017.3.30):回来再看自动机的时候重新写了一遍,感觉求h数组的部分不是很直观,所以改掉了。
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define mp make_pair #define maxn 5005 struct Suffix_Array{ int s[maxn]; int rk[maxn],cnt[maxn],sa[maxn],tmp[maxn],h[maxn]; void build(int n,int m) { int i,j,k; n++; F(i,0,2*n+5) tmp[i]=sa[i]=rk[i]=h[i]=0; F(i,0,m-1) cnt[i]=0; F(i,0,n-1) cnt[rk[i]=s[i]]++; F(i,1,m-1) cnt[i]+=cnt[i-1]; F(i,0,n-1) sa[--cnt[rk[i]]]=i; for (k=1;k<=n;k<<=1) { F(i,0,n-1) { j=sa[i]-k; if (j<0) j+=n; tmp[cnt[rk[j]]++]=j; } sa[tmp[cnt[0]=0]]=j=0; F(i,1,n-1) { if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i; sa[tmp[i]]=j; } memcpy(rk,sa,n*sizeof (int)); memcpy(sa,tmp,n*sizeof (int)); if (j>=n-1) break; } for (i=k=0;i<n;h[rk[i++]]=k) for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++); } }SA; char ss[maxn]; int ans=0,tt; int main() { scanf("%d",&tt); while (tt--) { ans=0; scanf("%s",ss); int n=strlen(ss); F(i,0,n-1) SA.s[i]=ss[i]; SA.s[n]=0; SA.build(n,256); F(i,1,n) ans+=n-SA.sa[i]-SA.h[i]; printf("%d\n",ans); } }