SPOJ 8222 Substrings 后缀自动机入门

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



题意:求一个字符串当中,长度为1,2..len的子串最多出现多少次。


根据字符串构造后缀自动机。

我们在每个节点上已经得到的最长的长度maxlen,则只要求出这个点的|right|,去更新ans[1...maxlen]就好了。实际上,只需要更新ans[maxlen],再O(n)的从长度较长的答案向长度小的答案更新。

而对于每个点的|right|,我们先把原串在自动机上跑一遍,把跑到的节点都设为1,其余设为0.之后,根据拓扑排序的关系从后向前推,即可获得每个点的|right|值。


#include <cstdio>
#include <iostream>
#include <string.h>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=250005,maxk=26,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;
int dp[maxn*2],f[maxn*2],w[maxn*2],r[maxn*2];
char s[maxn];

class SAM {  
    public:  
    void init() {  
        num=last=0;  
        a[0].len=0;a[0].fa=-1;  
        for (int i=0;i<maxk;i++) a[0].son[i]=-1;  
    }  
    void update (int c) {  
        int now=++num,p;  
        a[now].len=a[last].len+1;
        memset(a[now].son,-1,sizeof(a[now].son));  
        for (p=last;p!=-1&&a[p].son[c]==-1;p=a[p].fa)  
            a[p].son[c]=now;  
        if (p==-1) a[now].fa=0; else {  
            int q=a[p].son[c];  
            if (a[p].len+1==a[q].len) {  
                a[now].fa=q;  
            } else {  
                int ne=++num;  
                a[ne].len=a[p].len+1; 
                memcpy(a[ne].son,a[q].son,sizeof(a[q].son));  
                a[ne].fa=a[q].fa;  
                for (;p!=-1&&a[p].son[c]==q;p=a[p].fa)   
                    a[p].son[c]=ne;  
                a[q].fa=a[now].fa=ne;  
            }  
        }  
        last=now;  
    } 
    int getson(int n,int c) {
    	return a[n].son[c];
    }
    int getnum() {
    	return num;
    }
    int getfa(int n) {
    	return a[n].fa;
    }
    int getlen(int n) {
    	return a[n].len;
    }
    private:  
    int num,last;  
    struct node{  
        int len,fa;  
        int son[maxk];  
    } a[maxn*2];  
};  
SAM sa;  

int main() {
	int n,m,len,i,j;
	scanf("%s",s);
	len=strlen(s);
	sa.init();
	for (i=0;i<len;i++) {
		sa.update(s[i]-'a');
	}
	mem0(dp);
	int now=0;
	m=sa.getnum();
/*	for(i=0;i<=m;i++) {
		cout << sa.getfa(i) << endl;
	}*/
	for (i=0;i<len;i++) {
		now=sa.getson(now,s[i]-'a');
		dp[now]++;
	}
    mem0(w);
    for(i=0;i<=m;i++) w[sa.getlen(i)]++;  
    for(i=0;i<=len;i++) w[i]+=w[i-1];  
    for(i=m;i>=0;i--) r[--w[sa.getlen(i)]]=i;  
    for (i=m;i>0;i--) {
    	int to=sa.getfa(r[i]);
    	if (to!=-1) dp[to]+=dp[r[i]]; 
    }
    mem0(f);
    for (i=1;i<=m;i++) {
    	int p=sa.getlen(i);
		f[p]=max(f[p],dp[i]);
	}
	for (i=len-1;i>=1;i--) f[i]=max(f[i],f[i+1]);
	for (i=1;i<=len;i++) printf("%d\n",f[i]);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值