• BZOJ4566: [Haoi2016]找相同字符


    题解: 我们考虑对第一个串建SAM  另一个串在第一个上跑 我们预处理出第一个串在parent树中以当前字符结尾产生的价值且下传到儿子节点 等于每个节点维护了 他在parent 树中到根这条链的所有子串的价值和 那么我们在来计算合并价值 第二串跑的时候 找到位置匹配的最远位置 而且我们必然可以得到他的祖先节点一定也会被匹配到 所以加上预处理的价值以及当前匹配的最远距离的价值 累积答案即可

    /**************************************************************
        Problem: 4566
        User: c20161007
        Language: C++
        Result: Accepted
        Time:1800 ms
        Memory:57152 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    const int MAXN=4e5+10;
    #define ll long long
    using namespace std;
    #define link(x) for(edge *j=h[x];j;j=j->next)
    int dis[MAXN],fa[MAXN],ch[MAXN][26],size[MAXN],sz[MAXN];
    int cnt,cur,rt;
    char s1[MAXN],s2[MAXN];
    bool vis[MAXN];
    struct edge{int t;edge*next;}e[MAXN],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    void built(int x){
        int last=cur;cur=++cnt;dis[cur]=dis[last]+1;int p=last;size[cur]=1;
        for(;p&&!ch[p][x];p=fa[p])ch[p][x]=cur;
        if(!p)fa[cur]=rt;
        else{
            int q=ch[p][x];
            if(dis[p]+1==dis[q])fa[cur]=q;
            else{
                int nt=++cnt;dis[nt]=dis[p]+1;
                memcpy(ch[nt],ch[q],sizeof(ch[q]));
                fa[nt]=fa[q];fa[q]=fa[cur]=nt;
                for(;ch[p][x]==q;p=fa[p])ch[p][x]=nt;
            }
        }
    }
    int sa[MAXN],txt[MAXN];
    void dfs(int x,int pre){
        link(x){
            if(j->t!=pre){dfs(j->t,x);size[x]+=size[j->t];}
        }
    }
    void slove(){
        scanf("%s",s2+1);int t=strlen(s2+1);int temp=rt;
        ll ans=0;int len=0;
        for(int i=1;i<=t;i++){
            int t=s2[i]-'a';
            if(ch[temp][t])len++,temp=ch[temp][t];
            else{
                int p=temp;
                for(;p&&!ch[p][t];p=fa[p]);
                if(!p)temp=rt,len=0;
                else temp=ch[p][t],len=dis[p]+1;
            }
            if(temp!=rt)ans+=sz[fa[temp]]+1LL*size[temp]*max(0,len-dis[fa[temp]]);
        }
        printf("%lld
    ",ans);
        return ;
    }
    int main(){
        scanf("%s",s1+1);int len=strlen(s1+1);
        rt=cnt=cur=1;
        for(int i=1;i<=len;i++)built(s1[i]-'a');
        for(int i=1;i<=cnt;i++)add(fa[i],i);
        dfs(rt,0);
        for(int i=1;i<=cnt;i++)txt[dis[i]]++;
        for(int i=1;i<=cnt;i++)txt[i]+=txt[i-1];
        for(int i=cnt;i>=1;i--)sa[txt[dis[i]]--]=i;
        for(int i=1;i<=cnt;i++)sz[sa[i]]=sz[fa[sa[i]]]+1LL*(dis[sa[i]]-dis[fa[sa[i]]])*size[sa[i]];
        //for(int i=2;i<=cnt;i++)sz[i]=sz[fa[i]]+1LL*(dis[i]-dis[fa[i]])*size[i];
        slove();
    }
    

      

    4566: [Haoi2016]找相同字符

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 1109  Solved: 646
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

    输出一个整数表示答案

    Sample Input

    aabb
    bbaa

    Sample Output

    10
  • 相关阅读:
    Python-理解装饰器
    PHP-四种解析XML文件的方法
    学习-短信的上行(MO)和下行(MT)详解
    Linux-进程、进程组、作业、会话、控制终端详解
    Linux-进程基础
    Linux-查看进程的完整路径
    Linux-使用 screen 管理你的远程会话
    Python-常用字符串转换实例
    Python-闭包详解
    Git-Git Book阅读笔记
  • 原文地址:https://www.cnblogs.com/wang9897/p/9637199.html
Copyright © 2020-2023  润新知