[P6139] 模板广义后缀自动机 - 广义SAM
Posted mollnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[P6139] 模板广义后缀自动机 - 广义SAM相关的知识,希望对你有一定的参考价值。
Description
给定 (n) 个由小写字母组成的字符串 (s_1,s_2ldots s_n),求本质不同的子串个数。(不包含空串)
Solution
每个串插入完后将 SAM 指回 (root),这样建立广义 SAM 还是不够的,需要一些奇怪的特判(见代码中 //!
部分)
(具体分析先鸽了)
答案就是 (sum (maxlen[i]-minlen[i]+1))
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2000005;
struct SAM {
int len[N], ch[N][26], fa[N], ind, last;
SAM() { ind = last = 1; }
inline int extend(int id) {
if(ch[last][id] && len[last]+1==len[ch[last][id]]) return ch[last][id]; //!
int cur = (++ ind), p, tmp, flag = 0; //!
len[cur] = len[last] + 1;
for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
if (!p) fa[cur] = 1;
else {
int q = ch[p][id];
if (len[q] == len[p] + 1) fa[cur] = q;
else {
if(p==last) flag=1; //!
tmp = (++ ind);
len[tmp] = len[p] + 1;
for(int i=0;i<26;i++) ch[tmp][i] = ch[q][i];
fa[tmp] = fa[q];
for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
fa[cur] = fa[q] = tmp;
}
}
last = cur;
return flag ? tmp : cur;//!
}
void extend(string s)
{
for(int i=0;i<s.length();i++)
{
last = extend(s[i]-‘a‘);
}
last = 1;
}
int solve()
{
int ans=0;
for(int i=1;i<=ind;i++)
{
ans+=len[i]-len[fa[i]];
}
return ans;
}
} sam;
signed main() {
ios::sync_with_stdio(false);
int n;
string str;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>str;
sam.extend(str);
}
cout<<sam.solve()<<endl;
}
以上是关于[P6139] 模板广义后缀自动机 - 广义SAM的主要内容,如果未能解决你的问题,请参考以下文章
CF666E Forensic Examination(广义后缀自动机+线段树合并)