广义后缀自动机,求多个串的本质不同子串个数。
回文自动机求回文串个数
#include<bits/stdc++.h>
using namespace std;
const int maxn = 4e5+100;
char s[maxn];
int len;
int T;
int n,m;
struct SAM
{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2];
int ans;
void init()
{
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=0;
ans=0;
l[1]=0;
}
int inline newnode()
{
++cnt;
memset(nxt[cnt],0,sizeof nxt[cnt]);
fa[cnt]=l[cnt]=0;
return cnt;
}
void add(int c)
{
int p = last;
int np = newnode();
last = np;
l[np] = l[p]+1;
while (p&&!nxt[p][c])
{
nxt[p][c]=np;
p = fa[p];
}
if (!p)
{
fa[np]=1;
}
else
{
int q = nxt[p][c];
if (l[q]==l[p]+1)
{
fa[np] = q;
}
else
{
int nq = newnode();
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] = fa[q];
l[nq] = l[p]+1;
fa[np]=fa[q]=nq;
while (nxt[p][c]==q&&p!=0)
{
nxt[p][c]=nq;
p=fa[p];
}
}
}
}
long long query()
{
init();
int len=strlen(s+1);
for (int i=1; i<=len; i++)
{
add(s[i]-'a');
}
last=1;//广义后缀自动机 当加入一个新串时last=1
for(int i=len;i>=1;i--)
add(s[i]-'a');
long long sum=0;
for(int i=1;i<=cnt;i++)//求本质不同串个数
{
sum+=l[i]-l[fa[i]];
}
return sum;
}
} sam;
struct PAM
{
int len[maxn],fail[maxn],nxt[maxn][26],id[maxn],num[maxn],tot,last,L[maxn];//tot为本质不同回文串个数
long long siz[maxn];
void init()
{
len[0]=0;
fail[0]=1;
len[1]=-1;
fail[1]=0;
tot=1;
last=0;
memset(nxt[1],0,sizeof(nxt[1]));
memset(nxt[0],0,sizeof(nxt[0]));
memset(siz,0,sizeof(siz));
}
int new_node(int x)
{
int now=++tot;
memset(nxt[tot],0,sizeof(nxt[tot]));
len[now]=x;
return now;
}
void ins(int c,int n)
{
int u=last;
while(s[n-len[u]-1]!=s[n])u=fail[u];
if(nxt[u][c]==0)
{
int now=new_node(len[u]+2);
int v=fail[u];
while(s[n-len[v]-1]!=s[n])v=fail[v];
fail[now]=nxt[v][c];
nxt[u][c]=now;
num[now]=num[fail[now]]+1;
}
last=nxt[u][c];
siz[last]++;
L[n]=len[last];
id[last]=n;
}
} pam;
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
pam.init();
sam.init();
for(int i=1;i<=len;i++)
pam.ins(s[i]-'a',i);
printf("%lld\n",(sam.query()+pam.tot-1)/2);
return 0;
}