zoukankan      html  css  js  c++  java
  • BZOJ5417: [Noi2018]你的名字

    BZOJ5417: [Noi2018]你的名字

    https://lydsy.com/JudgeOnline/problem.php?id=5417

    分析:

    后缀数组 https://www.cnblogs.com/suika/p/9426839.html

    • 现在来看写出这样的代码应该不是什么问题了,感觉比(sa)好写。
    • 先建出(T)串的后缀自动机,由于求的是本质不同子串数量,直接在(T)串的后缀自动机上统计每个结点的贡献即可。
    • 那么我们只需求出每个结点能够向左匹配的长度(h_i)
    • 答案就是(sumlimits_i max(0,len[i]-max(len[fa[i]],h[i])))
    • 转化成求(T)每个前缀和(S)串匹配的后缀长度。
    • 这个和正常匹配差不多,有(ch)就走,然后在判断是否有一个(endpos)出现在特定区间内。
    • 如果没有就减少匹配长度并向上跳。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <iostream>
    using namespace std;
    #define N 1000050
    typedef long long ll;
    char w1[N],w2[N];
    int n,m,h[N];
    int siz[N*20],ls[N*20],rs[N*20],tot,root[N];
    int ke[N],ro[N],L,R;
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {
        int x=0; char s=nc();
        while(s<'0'||s>'9') s=nc();
        while(s>='0'&&s<='9') x=(((x<<2)+x)<<1)+s-'0',s=nc();
        return x;
    }
    char pbuf[100000],*pp=pbuf;
    void push(const char c) {
        if(pp-pbuf==100000) fwrite(pbuf,1,100000,stdout),pp=pbuf;
        *pp++=c;
    }
    void write(ll x) {
        static int sta[30];
        int top=0;
        do{sta[top++]=x%10,x/=10;}while(x);
        while(top) push(sta[--top]+'0'); push('
    ');
    }
    void update(int l,int r,int x,int &p) {
        if(!p) p=++tot;
        siz[p]++;
        if(l==r) return ;
        int mid=(l+r)>>1;
        if(x<=mid) update(l,mid,x,ls[p]);
        else update(mid+1,r,x,rs[p]);
    }
    int merge(int x,int y) {
        if(!x||!y) return x+y;
        int p=++tot;
        ls[p]=merge(ls[x],ls[y]);
        rs[p]=merge(rs[x],rs[y]);
        siz[p]=siz[ls[p]]+siz[rs[p]];
        return p;
    }
    int OK;
    void query(int l,int r,int x,int y,int p) {
        if(!p||OK) return ;
        if(x<=l&&y>=r) {if(siz[p])OK=1; return ;}
        int mid=(l+r)>>1;
        if(x<=mid) query(l,mid,x,y,ls[p]);
        if(y>mid) query(mid+1,r,x,y,rs[p]);
    }
    struct sam {
        int ch[N][26],len[N<<1],lst,cnt,fa[N<<1],tag[N<<1];
        void init() {lst=cnt=1;}
        void insert(int x,int id) {
            int p=lst,np=++cnt,q,nq;
            lst=np; len[np]=len[p]+1; tag[np]=id;
            for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
            if(!p) fa[np]=1;
            else {
                q=ch[p][x];
                if(len[q]==len[p]+1) fa[np]=q;
                else {
                    nq=++cnt; 
                    len[nq]=len[p]+1; tag[nq]=tag[q];
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    fa[nq]=fa[q];
                    fa[np]=fa[q]=nq;
                    for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
                }
            }
        }
        void kero() {
            int i;
            for(i=1;i<=cnt;i++) ke[len[i]]++;
            for(i=1;i<=cnt;i++) ke[i]+=ke[i-1];
            for(i=cnt;i;i--) ro[ke[len[i]]--]=i;
            for(i=cnt;i>1;i--) {
                int p=ro[i]; root[fa[p]]=merge(root[fa[p]],root[p]);
            }
        }
        void run() {
            int i,p=1,now=0;
            for(i=1;i<=m;i++) {
                int x=w2[i]-'a';
                if(ch[p][x]) {
                    p=ch[p][x]; now++;
                }else {
                    for(;p&&!ch[p][x];p=fa[p]) ;
                    if(!p) {p=1; now=0; h[i]=0; continue;}
                    else {
                        now=len[p]+1; p=ch[p][x];
                    }
                }
                if(L!=1||R!=n) {
                    while(1) {
                        OK=0;
                        query(1,n,L+now-1,R,root[p]);
                        if(OK) break;
                        now--; if(now==len[fa[p]]) p=fa[p];
                        if(!p) {
                            p=1; now=0; break;
                        }
                    }
                }
                h[i]=now;
            }
        }
        void get_ans() {
            ll ans=0; int i;
            for(i=2;i<=cnt;i++) {
                ans+=max(0,len[i]-max(len[fa[i]],h[tag[i]]));
            }
            write(ans);
            for(i=1;i<=cnt;i++) memset(ch[i],0,sizeof(ch[i])),len[i]=tag[i]=fa[i]=0;
        }
    }S,T;
    int main() {
        char s=nc();
        while(s<'a'||s>'z') s=nc();
        S.init();
        int i;
        for(;s>='a'&&s<='z';s=nc()) {
            w1[++n]=s;
        }
        for(i=1;i<=n;i++) {
            S.insert(w1[i]-'a',i);
            update(1,n,i,root[S.lst]);
        }
        S.kero();
        int q;
        q=rd();
        while(q--) {
            T.init();
            s=nc();
            m=0;
            while(s<'a'||s>'z') s=nc();
            for(;s>='a'&&s<='z';s=nc()) {
                w2[++m]=s;
            }
            L=rd(); R=rd();
            for(i=1;i<=m;i++) T.insert(w2[i]-'a',i);
            S.run();
            T.get_ans();
        }
        fwrite(pbuf,1,pp-pbuf,stdout);
    }
    
  • 相关阅读:
    POJ1741
    聪聪可可
    [USACO07NOV]Cow Relays
    Android 程序的反破解技术
    在Android上实现SSL握手(客户端需要密钥和证书),实现服务器和客户端之间Socket交互
    vmware中的bridge、nat、host-only的区别
    史上最易懂的Android jni开发资料--NDK环境搭建
    使用javah生成.h文件, 出现无法访问android.app,Activity的错误的解决
    Android apk反编译基础(apktoos)图文教程
    Smali文件语法解析
  • 原文地址:https://www.cnblogs.com/suika/p/10205412.html
Copyright © 2011-2022 走看看