[HAOI2016]找相同字符

∥☆過路亽.° 提交于 2020-02-06 05:17:36

一、题目

点此看题

二、解法

一般这种题都是在第一个字符串上建后缀自动机,然后第二个去乱搞。

我们先处理出每个节点的rightright集合大小sizsiz,然后把第二个串丢进去匹配,设匹配到的点为pp,长度为lenlen,则匹配到这个点的贡献为:
(lenlen[fa[p]])×siz[p](len-len[fa[p]])\times siz[p]匹配完之后还要以自动机上的节点再算一遍贡献(因为匹配时我们只算了下面的,没有算上面的),我们再匹配时对pp点打标记,设sum[i]sum[i]ii子树内的标记个数(不包含ii),那么这个点的贡献为:
sum[i]×(len[i]len[fa[i]])×siz[i]sum[i]\times(len[i]-len[fa[i]])\times siz[i]时间复杂度O(n)O(n),可以参考一下我的代码。

#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();
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!