标签:else 开始 表示 mem void 模板 code ext 数列
(刷的第一道后缀自动机)
正式开始后缀自动机的漫长道路
hihoCoder 1145
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中出现了多少不同的旋律?
共一行,包含一个由小写字母构成的字符串。字符串长度不超过 1000000。
一行一个整数,表示答案。
aab
#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;
}
标签:else 开始 表示 mem void 模板 code ext 数列
原文地址:https://www.cnblogs.com/kgs719/p/9853692.html