洛谷 P3181 [HAOI2016]找相同字符

来源:互联网 发布:淘宝加盟要多少钱 编辑:程序博客网 时间:2024/06/08 04:47

题目描述

给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。

输入输出格式

输入格式:

两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母

输出格式:

输出一个整数表示答案

输入输出样例

输入样例#1:
aabbbbaa
输出样例#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;}


0 0
原创粉丝点击