后缀自动机统计 子串长度出现次数 NSUBSTR - Substrings

#

You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string ‘ababa’ F(3) will be 2 because there is a string ‘aba’ that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.

Input

String S consists of at most 250000 lowercase latin letters.

Output

Output |S| lines. On the i-th line output F(i).

Example

  1. Input:
  2. ababa
  3. Output:
  4. 3
  5. 2
  6. 2
  7. 1
  8. 1

题意:给你一个字符串,统计每个长度出现的最大次数

思路:给后缀自动机主链每个点赋值为1 ,然后拓补排序,然后更新每个长度,

AC代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int M=5e5+5;
  4. struct Node{int ch[26],fa,len;}sam[M];
  5. char s[M];
  6. int n,siz[M],las=1,cnt=1,t[M],sa[M],res[M];
  7. void add(int c){
  8. int p=las;
  9. int np=las=++cnt;
  10. siz[cnt]=1;
  11. sam[np].len=sam[p].len+1;
  12. for(;p&&!sam[p].ch[c];p=sam[p].fa)sam[p].ch[c]=np;
  13. if(!p)sam[np].fa=1;
  14. else{
  15. int q=sam[p].ch[c];
  16. if(sam[q].len==sam[p].len+1)sam[np].fa=q;
  17. else{
  18. int nq=++cnt;
  19. sam[nq]=sam[q];
  20. sam[nq].len=sam[p].len+1;
  21. sam[np].fa=sam[q].fa=nq;
  22. for(;p&&sam[p].ch[c]==q;p=sam[p].fa)sam[p].ch[c]=nq;
  23. }
  24. }
  25. }
  26. int main(){
  27. scanf("%s",s+1);
  28. n=strlen(s+1);
  29. for(int i=1;i<=n;i++) add(s[i]-'a');
  30. for(int i=1;i<=cnt;i++) t[sam[i].len]++;
  31. for(int i=1;i<=cnt;i++) t[i]+=t[i-1];
  32. for(int i=1;i<=cnt;i++) sa[t[sam[i].len]--]=i;
  33. for(int i=cnt;i;i--){
  34. siz[sam[sa[i]].fa]+=siz[sa[i]];//使用自己更新父亲
  35. res[sam[sa[i]].len]=max(res[sam[sa[i]].len],siz[sa[i]]);//更新对应的长度
  36. }
  37. for(int i=n-1;i;i--)res[i]=max(res[i+1],res[i]);
  38. for(int i=1;i<=n;i++)printf("%d\n",res[i]);
  39. return 0;
  40. }

发表评论

表情:
评论列表 (有 0 条评论,56人围观)

还没有评论,来说两句吧...

相关阅读