spoj694/705 Distinct Substrings - 后缀数组
题目链接:http://acm.hust.edu.cn/vjudge/problem/19282
题目大意:求不同子串的个数
解题思路:后缀数组..
suffix(i)对子串个数所做的贡献为len-sa[i]+1,因为要求要不同的,所以减去与它串重复的子串个数h[i]。即每个后缀对答案的贡献为len-sa[i]+1-h[i];(***)
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; #define maxn 1100 int sa[maxn],rk[maxn],y[maxn],len; int Rsort[maxn],wr[maxn],h[maxn]; char s[maxn]; bool cmp(int x,int y,int ln){return (wr[x]==wr[y])&&(wr[x+ln]==wr[y+ln]);} void get_h() { int i,k=0; for (i=1;i<=len;i++) { int j=sa[rk[i]-1]; if (k>0) k--; while (s[i+k]==s[j+k]) k++; h[rk[i]]=k; } } void get_sa() { int i,k,p,ln,m=130; for (i=1;i<=len;i++) rk[i]=s[i]; for (i=0;i<=m;i++) Rsort[i]=0; for (i=1;i<=len;i++) Rsort[rk[i]]++; for (i=1;i<=m;i++) Rsort[i]+=Rsort[i-1]; for (i=len;i>=1;i--) sa[Rsort[rk[i]]--]=i; p=0;ln=1; while (p<len) { for (k=0,i=len-ln+1;i<=len;i++) y[++k]=i; for (i=1;i<=len;i++) if (sa[i]-ln>0) y[++k]=sa[i]-ln; for (i=1;i<=len;i++) wr[i]=rk[y[i]]; for (i=0;i<=m;i++) Rsort[i]=0; for (i=1;i<=len;i++) Rsort[wr[i]]++; for (i=1;i<=m;i++) Rsort[i]+=Rsort[i-1]; for (i=len;i>=1;i--) sa[Rsort[wr[i]]--]=y[i]; memcpy(wr,rk,sizeof(wr)); p=1;rk[sa[1]]=1; for (i=2;i<=len;i++) { if (!cmp(sa[i],sa[i-1],ln)) p++; rk[sa[i]]=p; }m=p;ln*=2; }sa[0]=s[0]=0; } int main() { int T,i;scanf("%d\n",&T); while (T--) { scanf("%s",s+1); len=strlen(s+1); get_sa();get_h(); LL ans=0;h[1]=0; for (i=1;i<=len;i++) { LL ls=sa[i]; ans+=len-ls+1-h[i]; }printf("%lld\n",ans); } return 0; }