您的位置:首页 > 其它

后缀自动机 重复旋律 5(求所有本质不同的子串)

2017-10-03 13:23 423 查看
后缀自动机二 重复旋律五

本题要求我们求出一个字符串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 );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: