zoukankan      html  css  js  c++  java
  • 【HNOI2016】—找相同字符(后缀自动机)

    传送门

    一道不错的题

    虽然不知道为什么一群DalaoDalao要用广义SamSam

    SamSam随便搞啊

    首先我们可以先对一个串建SamSam

    用另一个串在上面跑

    我们考虑对于第二个串的每一个结尾对答案的贡献数

    显然是ParentTreeParent-Tree上当前SamSam所在的点到的根的所有子串的大小
    当然这只是大概的一个说法,实际上不准确,应该是到根的所有点集合内的子串的个数(包括不同地方的不同串每个都算一个)之和,感性理解到意思就可以了

    现在考虑如何维护这样一个东西

    显然我们可以先计算出每个endposendpos集合endposendpos大小

    然后乘以这个集合内有的串的个数,也就是len[u]len[link[u]]len[u]-len[link[u]]

    因为我们也不可能一直向根跑来统计答案

    所以我们利用前缀和的思想,把计算出的值往下传

    这样最后每个点记录的就都是其到根的值了

    但是注意第二个串匹配的时候不能直接加上当前这个点的值

    应该是他linklink的值加上在这个集合的子串大小乘上endposendpos集合

    所以记录一下当前最长匹配的串长就可以了

    具体看代码更好理解一些

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    inline int read(){
        char ch=getchar();
        int res=0;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
        return res;
    }
    const int N=400005;
    int nxt[N][27],len[N],link[N],siz[N],A[N],p[N],ksiz[N],tot,last;
    char a[N];
    ll ans;
    inline void sa_extend(int c){
        int cur=++tot,p=last;last=tot;
        len[cur]=len[p]+1,siz[cur]=1;
        for(;p&&!nxt[p][c];p=link[p])nxt[p][c]=cur;
        if(!p)link[cur]=1;
        else{
            int q=nxt[p][c];
            if(len[q]==len[p]+1)link[cur]=q;
            else{
                int clo=++tot;
                memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
                link[clo]=link[q],len[clo]=len[p]+1;
                for(;p&&nxt[p][c]==q;p=link[p])nxt[p][c]=clo;
                link[cur]=link[q]=clo;
            }
        }
    }
    int main(){
        scanf("%s",a+1);last=tot=1;
        int lent=strlen(a+1);
        for(int i=1;i<=lent;++i)sa_extend(a[i]-'a');
        for(int i=1;i<=tot;i++)A[len[i]]++;
        for(int i=1;i<=tot;i++)A[i]+=A[i-1];
        for(int i=1;i<=tot;i++)p[A[len[i]]--]=i;
        for(int i=tot;i;--i)siz[link[p[i]]]+=siz[p[i]];
        for(int i=1;i<=tot;i++)
            ksiz[p[i]]=ksiz[link[p[i]]]+(len[p[i]]-len[link[p[i]]])*siz[p[i]];
        scanf("%s",a+1);
        lent=strlen(a+1);
        int p=1,let=0;
        for(int i=1;i<=lent;i++){
            int c=a[i]-'a';
            for(;p&&!nxt[p][c];p=link[p]);
            if(!p)let=0,p=1;
            else{
                let=min(len[p],let)+1,p=nxt[p][c];
                ans+=ksiz[link[p]]+(let-len[link[p]])*siz[p];
            }
        }
        cout<<ans;
    }
    
    
  • 相关阅读:
    010:请教STM32用JLINK V8 SWD输出调试信息到ITM Viewer的问题(转)
    014:针对mdk中STM32程序无法使用printf,产生停留BEAB BKPT 0xAB处问题的解决(转)
    011:Nuvoton(新唐) Cortex M0 使用semihost输入输出办法(转)
    015:6步教你在STM32程序中添加 printf函数(转)
    js定时和离开当前页面事件 明天
    linux常用命令 明天
    mongoDB常用命令 明天
    自定义标签的使用 明天
    浏览器事件 明天
    SonarQube简介
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366373.html
Copyright © 2011-2022 走看看