Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
将每一个单词读入,每一个单词中间用一个没有出现并小于前面字符的字符。之后用后缀数组算出公共前缀的height数组。
对于每个单词,向前后搜索,若公共前缀大于单词长度,说明出现过一次;
用来分隔的字符需要是最小的,我开始用最大的套模版,结果死循环了。。。。ORZ。会出现sa【0】==0的情况,貌似会挂。
代码:
/************************************************************** Problem: 3172 User: 1115825064 Language: C++ Result: Accepted Time:1308 ms Memory:33496 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1002001; int r[N],rank[N],wa[N],wb[N],ws1[N],wv[N],h[N],sa[N]; int p[210],l[210],n; bool cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int *x=wa,*y=wb,*t; for(int i=0;i<m;++i) ws1[i]=0; for(int i=0;i<n;++i) ws1[x[i]=r[i]]++; for(int i=1;i<m;++i) ws1[i]+=ws1[i-1]; for(int i=n-1;i>=0;i--) sa[--ws1[x[i]]]=i; for(int p1=1,j=1;p1<n;j*=2,m=p1) { p1=0; for(int i=n-j;i<n;i++) y[p1++]=i; for(int i=0;i<n;i++) if(sa[i]>=j) y[p1++]=sa[i]-j; for(int i=0;i<n;i++) wv[i]=x[y[i]]; for(int i=0;i<m;++i) ws1[i]=0; for(int i=0;i<n;++i) ws1[wv[i]]++; for(int i=1;i<m;++i) ws1[i]+=ws1[i-1]; for(int i=n-1;i>=0;--i) sa[--ws1[wv[i]]]=y[i]; t=x,x=y,y=t,p1=1,x[sa[0]]=0; for(int i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p1-1:p1++; } } void height(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<n;++i) rank[sa[i]]=i; for(i=0;i<n;h[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];++k); } int main() { scanf("%d",&n); int tot=0; for(int a,i=1;i<=n;++i) { char s[N]; scanf("%s",s); a=strlen(s); p[i]=tot; for(int j1=0;j1<a;++j1) r[j1+tot]=s[j1]-'a'+2; l[i]=a; tot+=a; r[tot++]=1; } da(r,sa,tot,30); height(r,sa,tot); for(int i=1;i<=n;++i) { int t=rank[p[i]],j,left,right; for(j=t;j&&h[j]>=l[i];j--); left=j; for(j=t+1;j<tot&&h[j]>=l[i];j++); right=j; printf("%d\n",right-left); } }