• 后缀自动机小专题


    菜鸡万年更博。

    全是菜题。

     

    SP1811 LCS - Longest Common Substring

    对一个串建立自动机,另一个串在自动机上遍历,失配时跳father更新即可。ans=遍历到的点的len的最大值。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=25e4+3;
    
    char S[N],T[N];
    
    struct SAM
    {
        int ch[26],fa,len;
    }sam[N<<1];
    
    int tot=1,lst=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;sam[lst].len=sam[p].len+1;
        for(;p&&!sam[p].ch[x];p=sam[p].fa) sam[p].ch[x]=lst;
        if(!p) sam[lst].fa=1;
        else
        {
            int q=sam[p].ch[x];
            if(sam[p].len+1==sam[q].len) sam[lst].fa=q;
            else
            {
                int nq=++tot;sam[nq]=sam[q],sam[nq].len=sam[p].len+1;
                sam[lst].fa=sam[q].fa=nq;
                for(;sam[p].ch[x]==q;p=sam[p].fa) sam[p].ch[x]=nq;
            }
        }
    }
    
    int main()
    {
        scanf("%s%s",S+1,T+1);
        for(int i=1;S[i];++i) insert(S[i]-'a');
        int now=1,len=0,Ans=0;
        for(int i=1;T[i];++i)
        {
            T[i]-='a';
            if(sam[now].ch[T[i]]) ++len,now=sam[now].ch[T[i]];
            else
            {
                while(now&&!sam[now].ch[T[i]]) now=sam[now].fa;
                if(!now) now=1,len=0;
                else len=sam[now].len+1,now=sam[now].ch[T[i]];
            }
            Ans=max(Ans,len);
        }
        cout<<Ans;
        return 0;
    }
    View Code

    SP1812 LCS2 - Longest Common Substring II

    可以跟上题一样做,也可以建个广义后缀自动机。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e5+5;
    
    int T,n;
    char s[N>>1];
    
    int ch[N][26],len[N],fa[N];
    
    int tot=1,lst=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];
                memmove(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=fa[lst]=nq;
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int cnt[N],sa[N];
    int mx[N],mn[N];
    int main()
    {
        scanf("%s",s+1);int sl=strlen(s+1);
        lst=tot=1;
        for(int i=1;i<=sl;++i) insert(s[i]-'a');
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=sl;++i) cnt[i]+=cnt[i-1];
        for(int i=1;i<=tot;++i) sa[cnt[len[i]]--]=i;
        memset(mn,0x3f,sizeof(mn));
        while(~scanf("%s",s+1))
        {
            int now=1,L=0,x;
            for(int i=1;s[i];++i)
            {
                x=s[i]-'a';
                while(now&&!ch[now][x]) now=fa[now],L=len[now];
                if(!now) now=1,L=0;
                else ++L,now=ch[now][x],mx[now]=max(mx[now],L);
            }
            for(int i=tot,u,f;i;--i)
            {
                u=sa[i],f=fa[u];
                mx[f]=max(mx[f],min(mx[u],len[f]));
                mn[u]=min(mn[u],mx[u]);mx[u]=0;
            }
        }
        int Ans=0;
        for(int i=1;i<=tot;++i) Ans=max(Ans,mn[i]);
        cout<<Ans<<'
    ';
        return 0;
    }
    View Code
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    #include<bitset>
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e6+5;
    
    int id=-1;
    char s[100003];
    
    struct SAM
    {
        int ch[26],fa,len;
        bitset<10> bst;
    }sam[N];
    
    int lst,tot=1;
    int newnode(int p,int q,int x)
    {
        int nq=++tot;sam[nq]=sam[q];sam[nq].len=sam[p].len+1;
        sam[q].fa=nq;
        for(;p&&sam[p].ch[x]==q;p=sam[p].fa) sam[p].ch[x]=nq;
        return nq;
    }
    
    int insert(int p,int x)
    {
        if(sam[p].ch[x])
        {
            int q=sam[p].ch[x];
            if(sam[p].len+1==sam[q].len)
            {
                sam[q].bst[id]=1;
                return q;
            }
            else
            {
                int nq=newnode(p,q,x);
                sam[nq].bst[id]=1;
                return nq;
            }
        }
        else
        {
            int np=++tot;sam[np].len=sam[p].len+1;sam[np].bst[id]=1;
            for(;p&&!sam[p].ch[x];p=sam[p].fa) sam[p].ch[x]=np;
            if(!p) sam[np].fa=1;
            else
            {
                int q=sam[p].ch[x];
                if(sam[p].len+1==sam[q].len) sam[np].fa=q;
                else sam[np].fa=newnode(p,q,x);
            }
            return np;
        }
    }
    
    void debug()
    {
        for(int i=1;i<=tot;++i)
        {
            for(int j=0;j<10;++j) cout<<sam[i].bst[j]<<' ';
            puts("");
        }
    }
    
    int cnt[N],sa[N];
    int main()
    {
        while(~scanf("%s",s+1))
        {
            lst=1;++id;
            for(int i=1;s[i];++i) lst=insert(lst,s[i]-'a');
        }
        for(int i=1;i<=tot;++i) ++cnt[sam[i].len];
        for(int i=1;i<=tot;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[sam[i].len]--]=i;
        int Ans=0;++id;
        for(int i=tot;i>1;--i)
        {
            if(sam[sa[i]].bst.count()==(unsigned)id) Ans=max(Ans,sam[sa[i]].len);
            sam[sam[sa[i]].fa].bst|=sam[sa[i]].bst;
        }
        cout<<Ans;
        return 0;
    }
    广义后缀自动机

    SP10570 LONGCS - Longest Common Substring

    三倍经验

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e4+5;
    
    int T,n;
    char s[N>>1];
    
    int ch[N][26],len[N],fa[N];
    
    int tot=1,lst=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];
                memmove(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=fa[lst]=nq;
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int cnt[N],sa[N];
    int mx[N],mn[N];
    int main()
    {
        T=read();
        while(T--)
        {
            n=read();scanf("%s",s+1);int sl=strlen(s+1);
            lst=tot=1;
            memset(ch,0,sizeof(ch));
            for(int i=1;i<=sl;++i) insert(s[i]-'a');
            memset(cnt,0,sizeof(cnt));
            for(int i=1;i<=tot;++i) ++cnt[len[i]];
            for(int i=1;i<=sl;++i) cnt[i]+=cnt[i-1];
            for(int i=1;i<=tot;++i) sa[cnt[len[i]]--]=i;
            memset(mn,0x3f,sizeof(mn));
            for(int a=2;a<=n;++a)
            {
                scanf("%s",s+1);
                int now=1,L=0,x;
                for(int i=1;s[i];++i)
                {
                    x=s[i]-'a';
                    while(now&&!ch[now][x]) now=fa[now],L=len[now];
                    if(!now) now=1,L=0;
                    else ++L,now=ch[now][x],mx[now]=max(mx[now],L);
                }
                for(int i=tot,u,f;i;--i)
                {
                    u=sa[i],f=fa[u];
                    mx[f]=max(mx[f],min(mx[u],len[f]));
                    mn[u]=min(mn[u],mx[u]);mx[u]=0;
                }
            }
            int Ans=0;
            for(int i=1;i<=tot;++i) Ans=max(Ans,mn[i]);
            cout<<Ans<<'
    ';
        }
        return 0;
    }
    View Code

    P3181 [HAOI2016]找相同字符

    求出每个子串在两个串中的出现次数,乘上每个点代表的不同子串个数len[p]-len[fa[p]]即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=8e5+5;
    
    char S[N>>2],T[N>>2];
    
    int id;
    int ch[N][26],len[N],fa[N],siz[2][N];
    
    int lst=1,tot=1;
    int newnode(int p,int x)
    {
        int q=ch[p][x],nq=++tot;len[nq]=len[p]+1;
        fa[nq]=fa[q],fa[q]=nq;memmove(ch[nq],ch[q],sizeof(ch[nq]));
        for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
        return nq;
    }
    
    int insert(int p,int x)
    {
        if(ch[p][x])
        {
            int q=ch[p][x];
            if(len[p]+1==len[q])
            {
                siz[id][q]=1;
                return q;
            }
            else
            {
                int nq=newnode(p,x);
                siz[id][nq]=1;
                return nq;
            }
        }
        else
        {
            int np=++tot;len[np]=len[p]+1,siz[id][np]=1;
            for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
            if(!p) fa[np]=1;
            else
            {
                int q=ch[p][x];
                if(len[p]+1==len[q]) fa[np]=q;
                else fa[np]=newnode(p,x);
            }
            return np;
        }
    }
    
    int cnt[N],sa[N];
    int main()
    {
        scanf("%s%s",S+1,T+1);
        lst=1,id=0;
        for(int i=1;S[i];++i)
            lst=insert(lst,S[i]-'a');
        lst=id=1;
        for(int i=1;T[i];++i)
            lst=insert(lst,T[i]-'a');
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=tot;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[len[i]]--]=i;
        LL ans=0;
        for(int i=tot;i>1;--i)
        {
            siz[0][fa[sa[i]]]+=siz[0][sa[i]],siz[1][fa[sa[i]]]+=siz[1][sa[i]];
            ans+=1ll*siz[0][sa[i]]*siz[1][sa[i]]*(len[sa[i]]-len[fa[sa[i]]]);
        }
        cout<<ans;
        return 0;
    }
    View Code

    P3975 [TJOI2015]弦论

    求出每个点后有多少串,然后按照字典序像splay一样二分出来就就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=1e6+5;
    
    int t,k;
    char s[N>>1];
    
    int ch[N][26],len[N],fa[N],siz[N];
    
    int tot=1,lst=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1,siz[lst]=1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q],siz[nq]=0;
                memmove(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=fa[lst]=nq;
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int f[N];
    int cnt[N],sa[N];
    int main()
    {
        scanf("%s",s+1);int n=strlen(s+1);
        t=read(),k=read();
        for(int i=1;i<=n;++i) insert(s[i]-'a');
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=1;i<=tot;++i) sa[cnt[len[i]]--]=i;
        for(int i=tot;i;--i)
        {
            if(!t) siz[sa[i]]=1;
            else siz[fa[sa[i]]]+=siz[sa[i]];
        }
        siz[0]=siz[1]=0;
        for(int i=tot;i;--i)
        {
            f[sa[i]]=siz[sa[i]];
            for(int j=0;j<26;++j) f[sa[i]]+=f[ch[sa[i]][j]];
        }
        if(f[1]<k){puts("-1");return 0;}
        int now=1;
        while(k>siz[now])
        {
            k-=siz[now];
            for(int i=0;i<26;++i)
            {
                if(k>f[ch[now][i]]) k-=f[ch[now][i]];
                else{putchar(i+'a');now=ch[now][i];break;}
            }
        }
        return 0;
    }
    View Code

    SP7258 SUBLEX - Lexicographical Substring Search

    跟上个一样的题。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e5+5;
    
    int T,k;
    char s[N>>1];
    
    int ch[N][26],fa[N],len[N];
    
    int lst=1,tot=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;fa[nq]=fa[q],len[nq]=len[p]+1;
                memmove(ch[nq],ch[q],sizeof(ch[q]));
                fa[lst]=fa[q]=nq;
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int f[N],cnt[N],sa[N];
    int main()
    {
        scanf("%s",s+1);
        for(int i=1;s[i];++i) insert(s[i]-'a');
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=tot;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[len[i]]--]=i;
        for(int i=tot;i;--i)
        {
            f[sa[i]]=1;
            for(int j=0;j<26;++j) f[sa[i]]+=f[ch[sa[i]][j]];
        }
        T=read();
        while(T--)
        {
            k=read();
            int now=1;
            while(k)
            {
                for(int i=0;i<26;++i)
                {
                    if(k>f[ch[now][i]]) k-=f[ch[now][i]];
                    else{putchar(i+'a');now=ch[now][i];--k;break;}
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    P4070 [SDOI2016]生成魔咒

    “每个点代表的不同子串个数是len[p]-len[fa[p]]”,每次插入ans加上len[lst]-len[fa[lst]]即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e5+5;
    
    int n;LL ans=0;
    int a[N];
    
    map<int,int> ch[N];int len[N],fa[N];
    
    int tot=1,lst=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;fa[nq]=fa[q],len[nq]=len[p]+1;
                fa[q]=fa[lst]=nq;ch[nq]=ch[q];
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
        ans+=len[lst]-len[fa[lst]];
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i)
        {
            insert(read());
            cout<<ans<<'
    ';
        }
        return 0;
    }
    View Code

    BZOJ 3277 串

    建广义后缀自动机,求出每个子串出现在几个串中看是否能产生贡献。每个点加上父亲的贡献,因为父亲一定会在这儿出现。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<string>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=2e5+5;
    
    int n,k;
    char s[N];
    string S[N];
    
    int ch[N][2],fa[N],len[N];
    
    int tot=1,lst;
    void insert(int p,int x)
    {
        lst=++tot;len[lst]=len[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;fa[nq]=fa[q],len[nq]=len[p]+1;
                fa[q]=fa[lst]=nq;memmove(ch[nq],ch[q],sizeof(ch[nq]));
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int vis[N],tims[N];
    void solve(string S,int x)
    {
        int now=1;int n=S.length();
        for(int i=0;i<n;++i)
        {
            now=ch[now][S[i]-'a'];
            for(int p=now;p&&vis[p]!=x;p=fa[p]) vis[p]=x,++tims[p];
        }
    }
    
    int sum[N];
    void query(string S)
    {
        int n=S.length();int ans=0;
        int now=1;
        for(int i=0;i<n;++i)
        {
            now=ch[now][S[i]-'a'];
            ans+=sum[now];
        }
        cout<<ans<<' ';
    }
    
    int cnt[N],sa[N];
    int main()
    {
        n=read(),k=read();
        for(int i=1;i<=n;++i)
        {
            scanf("%s",s+1);
            S[i]=string(s+1);
            int now=1;lst=1;
            for(int j=1;s[j];++j) insert(now,s[j]-='a'),now=ch[now][s[j]];
        }
        for(int i=1;i<=n;++i) solve(S[i],i);
        for(int i=1;i<=tot;++i)    sum[i]=(tims[i]>=k)*(len[i]-len[fa[i]]);
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=tot;++i) cnt[i]+=cnt[i-1];
        for(int i=1;i<=tot;++i) sa[cnt[len[i]]--]=i;
        for(int i=1;i<=tot;++i) sum[sa[i]]+=sum[fa[sa[i]]];
        for(int i=1;i<=n;++i) query(S[i]);
        return 0;
    }
    View Code

    P4248 [AHOI2013]差异

    把串倒着插入,两个子串的lcp长度就是他们在parent树上的祖先的长度。

    记录每个点子树的后缀个数,计算与它父亲的其他儿子产生的贡献=siz[p]*siz[fa[p]]*len[fa[p]]。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=1e6+5;
    
    char s[N>>1];
    
    int ch[N][26],len[N],fa[N],siz[N];
    
    int lst=1,tot=1;
    void insert(int x)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1,siz[lst]=1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;fa[nq]=fa[q],len[nq]=len[p]+1;
                fa[lst]=fa[q]=nq;memmove(ch[nq],ch[q],sizeof(ch[q]));
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int sa[N],cnt[N];
    int main()
    {
        scanf("%s",s+1);int n=strlen(s+1);
        for(int i=n;i;--i) insert(s[i]-'a');
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[len[i]]--]=i;
        LL ans=0;
        for(int i=tot;i>1;--i)
        {
            ans+=1ll*siz[sa[i]]*siz[fa[sa[i]]]*len[fa[sa[i]]];
            siz[fa[sa[i]]]+=siz[sa[i]];
        }
        cout<<1ll*(n-1)*n*(n+1)/2-2*ans;
        return 0;
    }
    View Code

    P2178 [NOI2015]品酒大会

    差不多和上个题一样。

    两个r相似的串可以看做是从p,q开始的两个后缀的lcp长度为r。

    最初ans1[r]求的是lcp恰好长为r的个数,ans2[r]求的是恰好为r的最大值。

    最后再求个后缀和和后缀max就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=6e5+5;
    const LL INF=0x3f3f3f3f3f3f3f3f;
    
    int n,a[N>>1];
    char s[N>>1];
    
    int ch[N][26],len[N],fa[N],siz[N];
    LL mx[N],mn[N];
    
    int lst=1,tot=1;
    void insert(int x,int v)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1,siz[lst]=1,mx[lst]=mn[lst]=v;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;len[nq]=len[p]+1,fa[nq]=fa[q];
                fa[q]=fa[lst]=nq;memmove(ch[nq],ch[q],sizeof(ch[nq]));
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    LL ans1[N],ans2[N];
    int sa[N],cnt[N];
    int main()
    {
        memset(ans2,-0x3f,sizeof(ans2));
        memset(mx,-0x3f,sizeof(mx));memset(mn,0x3f,sizeof(mn));
        n=read();scanf("%s",s+1);
        for(int i=1;i<=n;++i) a[i]=read();
        for(int i=n;i;--i) insert(s[i]-'a',a[i]);
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[len[i]]--]=i;
        for(int i=tot;i;--i)
        {
            ans1[len[fa[sa[i]]]]+=1ll*siz[fa[sa[i]]]*siz[sa[i]];
            if(mx[sa[i]]!=-INF&&mn[sa[i]]!=INF&&mx[fa[sa[i]]]!=-INF&&mn[fa[sa[i]]]!=INF)
            {
                ans2[len[fa[sa[i]]]]=max(ans2[len[fa[sa[i]]]],1ll*mx[sa[i]]*mx[fa[sa[i]]]);
                ans2[len[fa[sa[i]]]]=max(ans2[len[fa[sa[i]]]],1ll*mn[sa[i]]*mn[fa[sa[i]]]);
            }
            siz[fa[sa[i]]]+=siz[sa[i]];
            mx[fa[sa[i]]]=max(mx[fa[sa[i]]],mx[sa[i]]);
            mn[fa[sa[i]]]=min(mn[fa[sa[i]]],mn[sa[i]]);
        }
        for(int i=n-2;~i;--i) ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
        for(int i=0;i<n;++i) cout<<ans1[i]<<' '<<(ans1[i]?ans2[i]:0)<<'
    ';
        return 0;
    }
    View Code

    CF873F Forbidden Indices

    被禁止就当做没出现,否则当做出现。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=4e5+5;
    
    int n;
    char s[N>>1],t[N>>1];
    
    int ch[N][26],len[N],fa[N];
    int siz[N];
    
    int tot=1,lst=1;
    void insert(int x,bool flag)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1,siz[lst]=flag;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;len[nq]=len[p]+1,fa[nq]=fa[q];
                fa[lst]=fa[q]=nq;memmove(ch[nq],ch[q],sizeof(ch[q]));
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    int cnt[N],sa[N];
    int main()
    {
        n=read();scanf("%s%s",s+1,t+1);
        for(int i=1;i<=n;++i) insert(s[i]-'a',(t[i]!='1'));
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=tot;i;--i) sa[cnt[len[i]]--]=i;
        for(int i=tot;i;--i) siz[fa[sa[i]]]+=siz[sa[i]];
        LL ans=0;
        for(int i=1;i<=tot;++i)    ans=max(ans,1ll*len[i]*siz[i]);
        cout<<ans;
        return 0;
    }
    View Code

    CodeChef Killjee and k-th letter

    做不下去了, 还没有看懂它建后缀树的地方,等待zbq解答ing..

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #define pb push_back
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define lb lower_bound
    #define ub upper_bound
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    
    inline LL read()
    {
        char c=getchar();LL num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    const int N=4e5+5;
    
    int n;LL sum[N];
    char s[N>>1];
    
    int son[N][26];
    int ch[N][26],len[N],fa[N],rig[N],pos[N];
    
    int lst=1,tot=1;
    void insert(int x,int i)
    {
        int p=lst;lst=++tot;len[lst]=len[p]+1;++rig[lst],pos[lst]=i;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=lst;
        if(!p) fa[lst]=1;
        else
        {
            int q=ch[p][x];
            if(len[p]+1==len[q]) fa[lst]=q;
            else
            {
                int nq=++tot;fa[nq]=fa[q],len[nq]=len[p]+1;
                fa[q]=fa[lst]=nq;memmove(ch[nq],ch[q],sizeof(ch[nq]));
                for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    
    void prework()
    {
        static int cnt[N],sa[N];
        for(int i=1;i<=tot;++i) ++cnt[len[i]];
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=1;i<=tot;++i) sa[cnt[len[i]]--]=i;
        for(int i=tot,x,y;i;--i)
        {
            x=sa[i],y=fa[sa[i]];
            rig[y]+=rig[x],pos[y]=pos[x];
            son[y][s[pos[x]-len[y]]-'a']=x;
        }
    }
    
    int dfn[N],bound;
    void dfs(int u)
    {
        dfn[++bound]=u;
        for(int i=0;i<26;++i)
            if(son[u][i]) dfs(son[u][i]);
    }
    
    LL calc(int l,int r)
    {
        return 1ll*(l+r)*(r-l+1)/2;
    }
    
    int query(LL k)
    {
        int l=1,r=tot,mid;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(sum[mid]<k) l=mid+1;
            else r=mid-1;
        }
        k-=sum[l-1];int t=dfn[l],h=len[fa[t]]+1;l=h,r=len[t];
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(1ll*rig[t]*calc(h,mid)<k) l=mid+1;
            else r=mid-1;
        }
        k-=1ll*rig[t]*calc(h,l-1);
        k=(k-1)%l+1;
        return s[pos[t]-k+1];
    }
    
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);
        reverse(s+1,s+n+1);
        for(int i=1;i<=n;++i) insert(s[i]-'a',i);
        prework();dfs(1);
        for(int i=1;i<=bound;++i) sum[i]=sum[i-1]+1ll*calc(len[fa[dfn[i]]]+1,len[dfn[i]])*rig[dfn[i]];
        int Q=read(),G=0;
        while(Q--)
        {
            int p,ans;LL m;p=read(),m=read();
            LL k=1ll*p*G%m+1;
            G+=(ans=query(k));
            cout<<(char)ans<<'
    ';
        }
        return 0;
    }
    View Code
  • 相关阅读:
    根据包路径输出类列表
    Logback配置
    接口的幂等性
    mock获取入参数并动态设置返回值
    linux,日志查找技巧
    scrapy 一些坑
    Pyinstaller打包附带DLL、图标和压缩EXE方法
    scrapy 爬虫教程
    买房
    Python: 在CSV文件中写入中文字符
  • 原文地址:https://www.cnblogs.com/lovewhy/p/10704390.html
Copyright © 2020-2023  润新知