@spoj - nsubstr@ Substrings


@description@

给定一个仅包含小写字母的字符串 S,对于每一个 i 满足 1 <= i <= |S|,求长度为 i 的,在 S 中出现次数最多的串出现了多少次?

input
输入一个长度小于等于 250000 的,仅包含小写字母的串。

output
输出 |S| 行,第 i 行表示长度为 i 的在 S 中出现次数最多的串的出现次数。

sample input
ababa
sample output
3
2
2
1
1

@solution@

想想我们在后缀自动机中 end-pos 的含义:每一次出现的结束位置的集合。
我们要求解它出现了多少次,即要求解 |end-pos|。

再想想我们构建后缀自动机采用的是增量法。
每次加入一个字符,就会多出来一个以前从未出现过的一个新结束位置。

然后想想我们 fa 的含义,一个结点的 end-pos 必然是 fa 的 end-pos 的子集。
所以假如多出来一个新的结束位置,那么它会影响它所有的祖先。

最后,一个结点的最长子串长度必然大于它 fa 的最长子串,因此我们可以按照最长子串长度进行桶排序,再从后往前扫一边,更新父亲的值,就可以求解出每一个结点的出现次数。

假如某一个结点出现次数为 k,那么它的最长子串的所有后缀出现次数也一定大于等于 k,所以我们可以直接用 k 去更新最长子串长度的值,再从后往前用后一个去更新前一个。

@accepted code@

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 250000;
struct sam{
	sam *ch[26], *fa; int mx;
	sam *nxt; int siz;
}pl[2*MAXN + 5], *bin[MAXN + 5], *tcnt, *root, *lst;
void init() {
	tcnt = root = &pl[0];
	for(int i=0;i<26;i++)
		root->ch[i] = NULL;
	root->fa = NULL, root->mx = 0;
}
void add_bin(sam *x) {
	x->nxt = bin[x->mx];
	bin[x->mx] = x;
}
sam *newnode() {
	tcnt++;
	for(int i=0;i<26;i++)
		tcnt->ch[i] = NULL;
	tcnt->fa = NULL, tcnt->mx = 0;
	return tcnt;
}
void sam_extend(int x) {
	sam *cur = newnode(), *p = lst;
	cur->mx = lst->mx + 1, cur->siz = 1, lst = cur;
	add_bin(cur);
	while( p && !p->ch[x] )
		p->ch[x] = cur, p = p->fa;
	if( !p )
		cur->fa = root;
	else {
		sam *q = p->ch[x];
		if( q->mx == p->mx + 1 )
			cur->fa = q;
		else {
			sam *cne = newnode();
			(*cne) = (*q), cne->mx = p->mx + 1, cne->siz = 0;
			add_bin(cne);
			q->fa = cur->fa = cne;
			while( p && p->ch[x] == q )
				p->ch[x] = cne, p = p->fa;
		}
	}
}
char s[MAXN + 5]; int ans[MAXN + 5];
int main() {
	init(); lst = root;
	scanf("%s", s); int lens = strlen(s);
	for(int i=0;i<lens;i++)
		sam_extend(s[i] - 'a');
	for(int i=lens;i>=1;i--) {
		while( bin[i] ) {
			bin[i]->fa->siz += bin[i]->siz;
			ans[i] = max(ans[i], bin[i]->siz);
			bin[i] = bin[i]->nxt;
		}
	}
	for(int i=1;i<=lens;i++)
		printf("%d\n", ans[i]);
}

@details@

我们的 end-pos 大小并不等于子树大小,而是等于子树内非复制的(即每一次用增量法加入的)点的个数。

posted @ 2019-01-10 19:39  Tiw_Air_OAO  阅读(140)  评论(0编辑  收藏  举报