zoukankan      html  css  js  c++  java
  • SPOJ- Distinct Substrings(后缀数组&后缀自动机)

    Given a string, we need to find the total number of its distinct substrings.

    Input

    T- number of test cases. T<=20;
    Each test case consists of one string, whose length is <= 1000

    Output

    For each test case output one number saying the number of distinct substrings.

    Example

    Sample Input:
    2
    CCCCC
    ABABA

    Sample Output:
    5
    9

    Explanation for the testcase with string ABABA: 
    len=1 : A,B
    len=2 : AB,BA
    len=3 : ABA,BAB
    len=4 : ABAB,BABA
    len=5 : ABABA
    Thus, total number of distinct substrings is 9.

    题解:

    本题题意就是给你一个字符串,让你找它有多少不同的子串;

    其实就是SAM的板题,只要求每一个状态点的longest[i]-longest[fa[i]]的和就行了。

    但由于是后缀数组专题,还是用后缀数组写:

    参考代码:

      后缀自动机:

    #include<bits/stdc++.h>
    using namespace std;
    #define PI acos(-1.0)
    #define mkp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const int maxn=1e5+10;
    char s[maxn];
    struct SAM{
        ll ans;
        int fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26],last,cnt;
        void Init()
        {
            memset(nxt[1],0,sizeof(nxt[1]));
            last=cnt=1; ans=0;
            fa[1]=0;l[1]=0;
        }
        
        int NewNode()
        {
            ++cnt;
            memset(nxt[cnt],0,sizeof(nxt[cnt]));
            fa[cnt]=l[cnt]=0;
            return cnt;
        }
        
        void Add(int c)
        {
            int p=last,np=NewNode();
            last=np;l[np]=l[p]+1;
            while(p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p];
            if(!p) fa[np]=1;
            else
            {
                int q=nxt[p][c];
                if(l[q]==l[p]+1) fa[np]=q;
                else
                {
                    int nq=NewNode();
                    memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                    fa[nq]=fa[q];
                    l[nq]=l[p]+1;
                    fa[q]=fa[np]=nq;
                    while(nxt[p][c]==q) nxt[p][c]=nq,p=fa[p]; 
                }
            }
            ans+=(l[last]-l[fa[last]])*1ll;    
        }
        
        void Query()
        {
            Init();
            for(int i=0,len=strlen(s);i<len;++i) Add(s[i]-'A');
            printf("%lld
    ",ans);
        }
    } sam;
    
    int main()
    {
        int N;
        scanf("%d",&N);
        while(N--)
        {
            sam.Init();
            scanf("%s",s);
            sam.Query();
        }
        return 0;
    }
    View Code

      后缀数组:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define rint register int
    #define ini inline int
    #define maxn 1000050
    using namespace std;
    char str[maxn];
    int y[maxn<<1],x[maxn<<1],c[maxn];
    int sa[maxn],rk[maxn],height[maxn];
    int n,m,s[maxn];
    
    inline void get_SA() 
    {
        for(int i=1;i<=m;++i) c[i]=0;
        for(int i=1;i<=n;++i) ++c[x[i]=s[i]];
        for(int i=2;i<=m;++i) c[i]+=c[i-1];
        for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;
        for(int k=1;k<=n;k<<=1) 
        {
            int num=0;
            for(int i=n-k+1;i<=n;++i) y[++num]=i;
            for(int i=1;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k;
            for(int i=1;i<=m;++i) c[i]=0;
            for(int i=1;i<=n;++i) ++c[x[i]];
            for(int i=2;i<=m;++i) c[i]+=c[i-1]; 
            for(int i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
            swap(x,y);
            x[sa[1]]=1;
            num=1;
            for(rint i=2;i<=n;++i)
                x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
            if(num==n) break;
            m=num;
        }
    }
    inline void get_height() 
    {
        int k=0;
        for(int i=1;i<=n;++i) rk[sa[i]]=i;
        for(int i=1;i<=n;++i) 
        {
            if(rk[i]==1) continue;//第一名height为0
            if(k) --k;//h[i]>=h[i-1]-1;
            rint j=sa[rk[i]-1];
            while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) ++k;
            height[rk[i]]=k;//h[i]=height[rk[i]];
        }
    }
    int main() 
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",str+1);
            n=strlen(str+1);m=256;
            for(int i=1;i<=n;++i) s[i]=str[i]-'A'+1;
            get_SA();
            get_height();
            //for(int i=1;i<=n;++i) cout<<sa[i]<<" "<<height[i]<<endl;
            int ans=0;
            for(int i=1;i<=n;++i) ans+=n-sa[i]+1-height[i];
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    在线支付模块小结
    Tomcat服务器热启动,修改项目源代码时不需要每次都重启Tomcat
    使用myeclipse进行hibernate快速开发
    hibernate的核心类和接口
    Hibernate手动配置
    Java的字符串md5加密和文件md5
    JDBC操作mysql数据库(SqlHelper类封装)
    yum报错[Errno 14] PYCURL ERROR 22(更换yum源)
    Ajax技术
    手动配置开发struts项目
  • 原文地址:https://www.cnblogs.com/csushl/p/11205770.html
Copyright © 2011-2022 走看看