• BZOJ_4566_[Haoi2016]找相同字符_后缀自动机


    BZOJ_4566_[Haoi2016]找相同字符_后缀自动机

    Description

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

    Input

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

    Output

    输出一个整数表示答案

    Sample Input

    aabb
    bbaa

    Sample Output

    10

    对两个串建立广义后缀自动机。
    设siz[i][0],siz[i][1]分别表示这个串分别在两个串中出现多少次,这个后缀树上DP即可求出。
    答案就是(dep[p]-dep[fa[p]])*siz[p][0]*siz[p][1]。
    注意插入每个串之前要重置lst=1
     
    代码:
    #include <cstdio>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 800050
    typedef long long ll;
    int ch[N<<1][26],fa[N<<1],dep[N<<1],siz[N<<1][2],cnt=1,lst=1;
    int ws[N],a[N];
    char w[N],s[N];
    void insert(int x) {
        int p=lst,np,q,nq;
        if(ch[p][x]) {
            q=ch[p][x];
            if(dep[q]==dep[p]+1) lst=q;
            else {
                fa[nq=++cnt]=fa[q]; lst=nq;
                dep[nq]=dep[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=nq;
                for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }else {
            np=++cnt; lst=np; dep[np]=dep[p]+1;
            for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
            if(!p) fa[np]=1;
            else {
                q=ch[p][x];
                if(dep[q]==dep[p]+1) fa[np]=q;
                else {
                    fa[nq=++cnt]=fa[q];
                    dep[nq]=dep[p]+1;
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    fa[q]=fa[np]=nq;
                    for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
                }
            }
        }
    }
    void print() {
        int i,j;
        printf("test-------------------------------------------
    ");
        for(i=1;i<=cnt;i++) {
            printf("p=%d,siz=%d,dep=%d,fa=%d
    ",i,siz[i][0],dep[i],fa[i]);
            for(j=0;j<26;j++) {
                if(ch[i][j]) {
                    printf("ch(%d)(%c)=%d
    ",i,j+'a',ch[i][j]);
                }
            }
        }
        printf("lst=%d
    ",lst);
    }
    int main() {
        scanf("%s%s",w+1,s+1);
        int lw=strlen(w+1),ls=strlen(s+1);
        int i;
        for(i=1;i<=lw;i++) insert(w[i]-'a'),siz[lst][0]++;
        lst=1;
        for(i=1;i<=ls;i++) insert(s[i]-'a'),siz[lst][1]++;
        // print();
        for(i=1;i<=cnt;i++) ws[dep[i]]++;
        for(i=1;i<=cnt;i++) ws[i]+=ws[i-1];
        for(i=1;i<=cnt;i++) a[ws[dep[i]]--]=i;
        for(i=cnt;i;i--) {
            int p=a[i];
            siz[fa[p]][0]+=siz[p][0];
            siz[fa[p]][1]+=siz[p][1];
        }
        ll ans=0;
        for(i=cnt;i;i--) {
            int p=a[i];
            ans+=1ll*(dep[p]-dep[fa[p]])*siz[p][0]*siz[p][1];
        }
        printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    字典树+二叉树
    ##22
    简单代码优雅写
    全排列
    【持续更新】哟!又在写BUG啊!
    大整数加法和大整数乘法
    【框架编程思想】线数筛的高级应用(欧拉12题和欧拉21题)
    【持续更新】 用算法流程实现的代码块们
    记忆化
    资源收集
  • 原文地址:https://www.cnblogs.com/suika/p/9153109.html
Copyright © 2020-2023  润新知