[hiho一下 第128周] 后缀自动机

题目链接:https://hihocoder.com/problemset/problem/1445

求给定字符串s不同子串的个数

即求该字符串构成的后缀自动机里面包含了多少个后缀

等价于求这个后缀自动机里面的路径的个数


每个后缀自动机节点所包含的后缀集合大小为len[p] - len[ link[p] ]

其中len为该节点到根的长度,link为该节点的后缀链接

求和输出即可

#include 
#include 
#include 

#define N 2000050

using namespace std;
typedef long long LL;
int last,cnt,len[N],link[N],ch[N][27],sh[N],rt;
char s[N];

void ut(int &x,int y) { x = min(x,y); }

void add(int pos) {
	int x = s[pos] - 'a' + 1 , p , now;
	p = last; last = now = ++cnt; 
	sh[now] = len[now] = len[p] + 1;
	
	while (p && !ch[p][x]) ch[p][x] = now , ut(sh[now],sh[p]+1) , p = link[p];
	
	if (!p) 
		link[now] = rt;
	else {
		int q = ch[p][x];
		if (len[q] == len[p] + 1) 
			link[now] = q; 
		else {
			int t = ++cnt;
			sh[t] = len[t] = len[p] + 1;
			memcpy(ch[t],ch[q],sizeof(ch[q]));
			link[t] = link[q];
			link[now] = link[q] = t;
			while (ch[p][x] == q) {
				ch[p][x] = t; 
				ut(sh[t],sh[p]+1);
				p = link[p];
			}
		}
	}
	return ;
}

int main() {
	last = rt = cnt = 1;
	scanf("%s",s+1); int n = strlen(s+1);
	for (int i=1;i<=n;i++) add(i);
	LL ans = 0LL;
	for (int i=2;i<=cnt;i++) ans += len[i] - len[ link[i] ];
	cout << ans << endl;
	return 0;
}


你可能感兴趣的:(后缀自动机)