题目描述
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。
输入输出格式
输入格式:
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
输出格式:
输出一个整数表示答案
输入输出样例
输入样例#1:
aabb bbaa
输出样例#1:
10
【分析】
广义后缀自动机QAQ,吼厉害QAQ
可我还是不太懂啊QAQ,等wxl回来了让他讲讲
【代码】
//bzoj 找相同字符
//传说中的广义后缀自动机= =
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=800005;
ll ans=0;
struct edge {int to,next;} f[mxn];
char s[mxn],ss[mxn];
int b[mxn],t[mxn],head[mxn];
int tmp,len,p,q,np,nq,tot,cnt,root;
int son[mxn][28],step[mxn],pre[mxn],size[mxn][2];
inline void add(int u,int v)
{
f[++cnt].to=v,f[cnt].next=head[u],head[u]=cnt;
}
inline void sam(int x) //为什么我写的sam自带大代码复杂度 QAQ
{
int i,j;
scanf("%s",s+1);
len=strlen(s+1);
np=1;
if(!x) tmp=len;
fo(i,1,len)
{
int c=s[i]-'a'+1;
p=np;
step[np=(++tot)]=step[p]+1;
size[np][x]++; //主链++(代表一些串)
while(p && !son[p][c])
son[p][c]=np,p=pre[p];
if(!p)
{
pre[np]=root;
continue;
}
q=son[p][c];
if(step[q]==step[p]+1)
pre[np]=q;
else
{
step[nq=(++tot)]=step[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
while(p && son[p][c]==q)
son[p][c]=nq,p=pre[p];
}
}
}
inline void dfs(int u)
{
for(int i=head[u];i;i=f[i].next)
{
int v=f[i].to;
dfs(v);
size[u][0]+=size[v][0];
size[u][1]+=size[v][1];
}
}
inline void solve()
{
int i,j;
fo(i,1,tot) add(pre[i],i);
dfs(1);
fo(i,1,tot) ans+=(ll)(step[i]-step[pre[i]])*size[i][0]*size[i][1];
printf("%lld\n",ans);
}
int main()
{
int i,j;
root=tot=1;
sam(0),sam(1);
len+=tmp;
solve();
return 0;
}