一、题目
二、解法
一般这种题都是在第一个字符串上建后缀自动机,然后第二个去乱搞。
我们先处理出每个节点的集合大小,然后把第二个串丢进去匹配,设匹配到的点为,长度为,则匹配到这个点的贡献为:
匹配完之后还要以自动机上的节点再算一遍贡献(因为匹配时我们只算了下面的,没有算上面的),我们再匹配时对点打标记,设为子树内的标记个数(不包含),那么这个点的贡献为:
时间复杂度,可以参考一下我的代码。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 400005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n;char s[M];
struct node
{
int len,fa,ch[26];
node() {memset(ch,0,sizeof ch);len=fa=0;}
};
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
};
struct automaton
{
int cnt,last,siz[M],sum[M],g[M];node a[M];
int tot,f[M];edge e[2*M];long long ans;
automaton() {cnt=last=1;}
void add(int c)
{
int p=last,np=last=++cnt;
a[np].len=a[p].len+1;siz[np]=1;
for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++cnt;
a[nq]=a[q];a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
}
}
}
void link(int u,int v)
{
e[++tot]=edge(v,f[u]),f[u]=tot;
e[++tot]=edge(u,f[v]),f[v]=tot;
}
void dfs(int u,int type)
{
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==a[u].fa) continue;
dfs(v,type);
if(type==0) siz[u]+=siz[v];
else sum[u]+=sum[v]+g[v];
}
}
void solve()
{
for(int i=2;i<=cnt;i++) link(i,a[i].fa);
dfs(1,0);
int len=0,p=1;
for(int i=0;i<n;i++)
{
int c=s[i]-'a';
if(a[p].ch[c]) p=a[p].ch[c],len++;
else
{
for(;p && !a[p].ch[c];p=a[p].fa);
if(p) len=a[p].len+1,p=a[p].ch[c];
else len=0,p=1;
}
ans+=1ll*(len-a[a[p].fa].len)*siz[p];
g[p]++;
}
dfs(1,1);
for(int i=1;i<=cnt;i++) ans+=1ll*(a[i].len-a[a[i].fa].len)*siz[i]*sum[i];
printf("%lld\n",ans);
}
}Sam;
int main()
{
scanf("%s",s);
n=strlen(s);
for(int i=0;i<n;i++)
Sam.add(s[i]-'a');
scanf("%s",s);
n=strlen(s);
Sam.solve();
}
来源:CSDN
作者:C202044zxy
链接:https://blog.csdn.net/C202044zxy/article/details/104188547