Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
a
aa
aaa
Sample Output
6
3
1
3
1
HINT
Source
思维越来越僵化。。。又是一道后缀数组傻逼题。。。
把所有的串拼在一起,中间用"#"隔开,然后记录每个串开始的位置st[i]和长度le[i]。
因为n很小可以每个串暴力;如果该串在别的串出现,那么以st[i]开头的后缀与别的后缀的lcp长度为le[i];
因为排名越靠近height越大,所以从rnk[st[i]]往左右两边扫,直到height小于le[i],则分组中的lcp长度为le[i],是所有的出现情况。
(upd:我发现我真的是头猪,while暴跳的话复杂度可能是平方的。。。正确的做法是要左右两边二分答案然后check LCP)
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=3000050; int gi(){ int x=0,flag=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*flag; } int sa[N],y[N],rnk[N],height[N],len,rk,le[N],st[N],n; char ch[N],a[N]; struct data{ int x1,x2,id; }x[N]; bool cmp(const data &a,const data &b){ if(a.x1==b.x1) return a.x2<b.x2; else return a.x1<b.x1; } void work2(){ int rk=1;y[x[1].id]=1; for(int i=2;i<=len;i++){ if(x[i].x1!=x[i-1].x1||x[i].x2!=x[i-1].x2) rk++; y[x[i].id]=rk; } } void work(){ sort(x+1,x+1+len,cmp);work2(); for(int i=1;i<=len;i<<=1){ for(int j=1;j+i<=len;j++) x[j].id=j,x[j].x1=y[j],x[j].x2=y[j+i]; for(int j=len-i+1;j<=len;j++) x[j].id=j,x[j].x1=y[j],x[j].x2=0; sort(x+1,x+1+len,cmp);work2(); if(rk==len) break; } } void get_height(){ int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i; for(int i=1;i<=len;i++){ if(kk) kk--; int j=sa[rnk[i]-1]; while(a[i+kk]==a[j+kk]) kk++; height[rnk[i]]=kk; } } void work3(int i){ ll ret=1;int l=rnk[st[i]],r=rnk[st[i]]+1; while(height[l]>=le[i]) ret++,l--; while(height[r]>=le[i]) ret++,r++; printf("%lld ",ret); } int main(){ n=gi(); for(int i=1;i<=n;i++){ scanf("%s",ch+1);le[i]=strlen(ch+1);st[i]=len+1; for(int j=1;j<=le[i];j++) a[len+j]=ch[j]; len+=le[i]+1;a[len]='#'; } for(int i=1;i<=len;i++) x[i].id=i,x[i].x1=x[i].x2=a[i]-'a'+1; work();for(int i=1;i<=len;i++) sa[y[i]]=i; get_height(); for(int i=1;i<=n;i++) work3(i); return 0; }