后缀自动机二 重复旋律五
本题要求我们求出一个字符串S中本质不同的子串个数。
显然,答案就是所有状态上的子串个数之和,这里说的一个状态上的子串个数,是longest-shortest+1。主要需要学习的是,后缀自动机的O(N)构建方法。需要了解的是,一个状态u的shortest=fail.longest+1。
#include <bits/stdc++.h>
using namespace std;
const int mxn = 2000100;
namespace suffixAuttomaton{
int tail=2;
int fail[mxn];
int maxi[mxn];
int mini[mxn];
int next[mxn][26];
inline int extend(int p,int c)
{
int t=tail++;
maxi[t]=maxi[p]+1;
while(p&&!next[p][c])
next[p][c]=t,p=fail[p];
if(p)
{
int q=next[p][c];
if(maxi[q]==maxi[p]+1)
fail[t]=q,mini[t]=maxi[q]+1;
else
{
int k=tail++;
fail[k]=fail[q];
fail[q]=fail[t]=k;
maxi[k]=maxi[p]+1;
mini[q]=maxi[k]+1;
mini[t]=maxi[k]+1;
for(int i=0;i<26;i++)
next[k][i]=next[q][i];
while(p&&next[p][c]==q)
next[p][c]=k,p=fail[p];
mini[k]=maxi[fail[k]]+1;
}
}
else fail[t]=1,mini[t]=1;
return t;
}
}
using namespace suffixAuttomaton;
int n;
char s[mxn];
int main()
{
scanf("%s",s);
n=strlen(s);
int last=1;
for(int i=0;i<n;i++)
last=extend(last,s[i]-'a');
long long ans=0;
for(int i=2;i<tail;i++)
ans+=maxi[i]-mini[i]+1;
printf("%lld\n",ans );
}