[后缀自动机] hihoCoder 1145

(刷的第一道后缀自动机)

正式开始后缀自动机的漫长道路

hihoCoder 1145

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

描述

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

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

输入

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

输出

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

样例输入
aab
样例输出
    5
思路:
  对所有状态st求Σ(maxlen(st)-minlen(st))(模板自带-1所以这里不用,到时候更懂的时候补充)

  裸题,建完图后直接求就行了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;;
char s[maxn]; 
struct Sam {
	int next[maxn << 1][26];
	int link[maxn << 1], step[maxn << 1];//step 
	int a[maxn], b[maxn << 1];
	int sz, last, root;
	void init() {
		//如多次建立自动机,加入memset操作
		root = sz = last = 1;
	}
	void add(int c) {
		int p = last;
		int np = ++sz;
		last = np;
		step[np] = step[p] + 1;
		while(!next[p][c] && p) {
			next[p][c] = np;
			p = link[p];
		}
		if(p == 0) {
			link[np] = root;
		} else {
			int q = next[p][c];
			if(step[p] + 1 == step[q]) {
				link[np] = q;
			} else {
				int nq = ++sz;
				memcpy(next[nq], next[q], sizeof(next[q]));
				step[nq] = step[p] + 1;
				link[nq] = link[q];
				link[q] = link[np] = nq;
				while(next[p][c] == q && p) {
					next[p][c] = nq;
					p = link[p];
				}
			}
		}
	}
	void build() {
		init();
		for(int i = 0; s[i]; i++) {
			add(s[i] - 'a');
		}
		for(int i = 1; i <= sz; i++) {
			a[step[i]]++;
		}
		for(int i = 1; i <= step[last]; i++) {
			a[i] += a[i - 1];
		}
		for(int i = 1; i <= sz; i++) {
			b[a[step[i]]--] = i;
		}
	}
} sam;
int main()
{
	cin>>s;
	long long ans = 0;
	sam.build();
	for(int i = 1;i<=sam.sz;i++)
	{
		ans+=sam.step[i]-sam.step[sam.link[i]];
	//	cout<<ans<<" += "<<sam.step[i]<<" - "<<sam.step[sam.link[i]]<<endl;
	}
	cout<<ans<<endl;
} 

  

posted @ 2018-10-25 23:57  咸鱼洲斩咸鱼风  阅读(156)  评论(0编辑  收藏  举报