hihocoder #1445 : 后缀自动机二·重复旋律5

#1445 : 后缀自动机二·重复旋律5

时间限制:10000ms
单点时限:2000ms
内存限制:512MB

描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。

现在小Hi想知道一部作品中出现了多少不同的旋律?

解题方法提示

输入

共一行,包含一个由小写字母构成的字符串。字符串长度不超过 1000000。

输出

一行一个整数,表示答案。

样例输入
aab
样例输出
5

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=2000000+5;

int last=1,tail=1,Min[maxn],Max[maxn],nxt[maxn][26],fail[maxn];

char s[maxn];

inline void build(char *s){
	while(*s){
		int p=last,t=++tail,c=*s++-'a';
		Max[t]=Max[p]+1;
		while(p&&!nxt[p][c])
			nxt[p][c]=t,p=fail[p];
		if(p){
			int q=nxt[p][c];
			if(Max[q]==Max[p]+1)
				fail[t]=q,Min[t]=Max[q]+1;
			else{
				int k=++tail;
				fail[k]=fail[q];
				fail[t]=fail[q]=k;
				Max[k]=Max[p]+1;
				Min[q]=Max[k]+1;
				Min[t]=Max[k]+1;
				Min[k]=Max[fail[k]]+1;
				memcpy(nxt[k],nxt[q],26*sizeof(int));
				while(nxt[p][c]==q)
					nxt[p][c]=k,p=fail[p];
			}
		}
		else
			fail[t]=1,Min[t]=1;
		last=t;
	}
}

inline void calc(void){
	long long ans=0;
	for(int i=2;i<=tail;i++)
		ans+=Max[i]-Min[i]+1;
	printf("%lld\n",ans);
}

signed main(void){
	scanf("%s",s);build(s);calc();
	return 0;
}

  


$By NeighThorn$

 
 
posted @ 2017-04-20 08:46  NeighThorn  阅读(465)  评论(0编辑  收藏  举报