SPOJ - 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

Input:
ababa

Output:
3
2
2
1
1

 

依次输出“出现次数最多的长度为x的字符串”的出现次数 (1<=x<=n)

 

后缀自动机

建出后缀自动机,统计每个节点标记的长度的出现次数即可。注意要倒序更新,把子节点(长串)的值累加到fa结点(长串的子串)的值上。

  ↑建好后缀自动机以后,要用原串在自动机上跑一便,每一个到达结点的初始次数r置为1。刚开始傻傻地把所有节点的r都初始化成1了,导致统计错误(理解不透彻)

顿悟:把后缀自动机的fa指针看成fail而不是father更直观 ←大概是我自己火星了)

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int mxn=500010;
 9 int read(){
10     int x=0,f=1;char ch=getchar();
11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return x*f;
14 }
15 struct SAM{
16     int t[mxn][26];
17     int fa[mxn],l[mxn],r[mxn],rk[mxn];
18     int S,cnt,last;
19     int f[mxn],w[mxn];
20     void init(){S=cnt=last=1;return;}
21     void add(int c){
22         int p=last,np=++cnt;last=np;
23         l[np]=l[p]+1;
24         for(;p && !t[p][c];p=fa[p])t[p][c]=np;
25         if(!p){fa[np]=S;}
26         else{
27             int q=t[p][c];
28             if(l[q]==l[p]+1){fa[np]=q;}
29             else{
30                 int nq=++cnt;l[nq]=l[p]+1;
31                 memcpy(t[nq],t[q],sizeof t[q]);
32                 fa[nq]=fa[q];
33                 fa[np]=fa[q]=nq;
34                 for(;p && t[p][c]==q;p=fa[p])t[p][c]=nq;
35             }
36         }
37     }
38     void st(char *s,int n){
39 //        for(int i=1;i<=cnt;i++){r[i]=1;w[l[i]]++;}
40         int p=S;
41         for(int i=1;i<=n;i++){
42             p=t[p][s[i]-'a'];
43             r[p]++;
44         }
45         for(int i=1;i<=cnt;i++){w[l[i]]++;}
46         for(int i=1;i<=n;i++)w[i]+=w[i-1];
47         for(int i=1;i<=cnt;i++)rk[w[l[i]]--]=i;
48         return;
49     }
50     void solve(int n){
51         for(int i=cnt;i;i--){
52             int t=rk[i];
53             f[l[t]]=max(f[l[t]],r[t]);
54             r[fa[t]]+=r[t];
55         }
56         for(int i=n-1;i;i--)f[i]=max(f[i],f[i+1]);
57         return;
58     }
59 }sa;
60 char s[mxn];
61 int main(){
62     int i,j;
63     sa.init();
64     scanf("%s",s+1);
65     int len=strlen(s+1);
66     for(i=1;i<=len;i++){
67         sa.add(s[i]-'a');
68     }
69     sa.st(s,len);
70     sa.solve(len);
71     for(i=1;i<=len;i++)printf("%d\n",sa.f[i]);
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/6420565.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值