zoukankan      html  css  js  c++  java
  • [Noi2016]优秀的拆分

    来自F allDream的博客,未经允许,请勿转载,谢谢。


    如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的。

    例如,对于字符串 aabaabaa,如果令 A=aab,B=a,我们就找到了这个字符串拆分成 AABB的一种方式。

    一个字符串可能没有优秀的拆分,也可能存在不止一种优秀的拆分。比如我们令 A=a,B=baa,也可以用 AABB表示出上述字符串;但是,字符串 abaabaa 就没有优秀的拆分。

    现在给出一个长度为 n的字符串 S,我们需要求出,在它所有子串的所有拆分方式中,优秀拆分的总个数。这里的子串是指字符串中连续的一段。

    以下事项需要注意:

    1.出现在不同位置的相同子串,我们认为是不同的子串,它们的优秀拆分均会被记入答案。

    2.在一个拆分中,允许出现 A=B。例如 cccc 存在拆分 A=B=c。

    3.字符串本身也是它的一个子串

    你需要计算一个字符串的所有子串的优秀的拆分的个数之和

    T(T<=10)组数据,n<=30000

    这道题n^2暴力95分..

    正解的话反正我是想不到...

    如果知道以每个点为左/右端点构成AA的方案数,就可以计算答案

    考虑求出正着反着各求出后缀数组之后,枚举长度L,然后每段长度是L把这个字符串分段

    每次枚举两个端点i,j(i和j都是L的倍数,j=i+L),并且计算左端点在[i-L+1,i]内的答案。

    所以求一下点i,j正着的lcp,反着的lcp,也就是从点i开始能向左右扩展到哪里,如果能扩展到的长度大等于L,那么就有答案

    假设倒着时候的lcp是a,正着的是b,也就是[i-a+1,i]和[j-a+1,j]相同(显然a>0),b同理,那么有答案的左端点区间是[i-a+1,i-a+1 + (a+b-1-L) -1] 差分即可。

    复杂度Tnlogn

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MN 30000
    #define MD 15
    using namespace std;
    inline int read()
    {
        int x = 0; char ch = getchar();
        while(ch < '0' || ch > '9') ch = getchar();
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x;
    }
    
    int n,k,lt[MN+5],rt[MN+5],v[MN+5],Log[MN+5];ll ans;
    char st[MN*2+5],st2[MN*2+5];
    
    void CalSa(int*SA,int*RK,int*sa,int*rk)
    {
        for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
        for(int i=n;i;--i)
            if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
        for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
        for(int i=1;i<=n;++i)
            RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
    }
    
    void GetH(int*H,int*sa,int*rk,char*s)
    {
        for(int i=1,k=0;i<=n;H[rk[i++]-1]=k,k?--k:0) if(rk[i]>1)
            for(int j=sa[rk[i]-1];s[j+k]==s[i+k];++k);
        
    }
    
    struct SuffixArray
    {
        int p,q,sa[2][MN+5],rk[2][MN+5],f[MD+1][MN+5],F[MD+1][MN+5],fa[MD+1][MN+5],Fa[MD+1][MN+5];
        inline void Clear(){p=1;q=0;
            memset(rk,0,sizeof(rk));
            memset(sa,0,sizeof(sa));
        }
        void Build(char *s)
        {
            memset(v,0,sizeof(int)*30);
            for(int i=1;i<=n;++i)++v[s[i]-'a'];
            for(int i=1;i<26;++i) v[i]+=v[i-1];
            for(int i=1;i<=n;++i) sa[q][v[s[i]-'a']--]=i;
            for(int i=1;i<=n;++i)
                rk[q][sa[q][i]]=rk[q][sa[q][i-1]]+(s[sa[q][i]]!=s[sa[q][i-1]]);
            for(k=1;k<n;k<<=1)
            {
                CalSa(sa[p],rk[p],sa[q],rk[q]);
                swap(p,q);
            }
        }
        void BuildHeight(char *s)
        {
            GetH(f[0],sa[q],rk[q],s);
            for(int i=2;i<=n;++i) F[0][i]=f[0][i-1];
            for(int i=0;i<=MD;++i) F[i][0]=f[i][0]=f[i][n]=F[i][1]=MN;
            for(int i=1;i<n;++i) fa[0][i]=i+1,Fa[0][i+1]=i;
            for(int i=1;i<=MD;++i)
                for(int j=1;j<=n;++j)
                    fa[i][j]=fa[i-1][fa[i-1][j]],
                    Fa[i][j]=Fa[i-1][Fa[i-1][j]],
                     f[i][j]=min(f[i-1][j],f[i-1][fa[i-1][j]]),
                     F[i][j]=min(F[i-1][j],F[i-1][Fa[i-1][j]]);
        }
        int query(int i,int j)
        {
            i=rk[q][i],j=rk[q][j];
            if(i>j) swap(i,j);
            int L=Log[j-i];
            return min(f[L][i],F[L][j]);
        }
    }P,S;
    
    int main()
    {
        Log[0]=-1;
        for(int i=1;i<=MN;++i) Log[i]=Log[i>>1]+1;
        for(int T=read();T;--T)
        {
            scanf("%s",st+1);n=strlen(st+1);
            for(int i=1;i<=n;++i) st2[i]=st[n-i+1];
            P.Clear();S.Clear();ans=0;
            P.Build(st);S.Build(st2);
            P.BuildHeight(st);
            S.BuildHeight(st2);
            memset(lt,0,sizeof(lt));
            memset(rt,0,sizeof(rt));
            for(int L=1;L<=n;++L)
                for(int i=L,j=i+L;j<=n;i=j,j+=L)
                {
                    int a=P.query(i,j),b=S.query(n-j+1,n-i+1);
                    if(min(a,L)+min(b,L)-1>=L)
                    {
                        int len=min(a,L)+min(b,L)-1-L;
                        ++lt[i-min(b,L)+1],--lt[i-min(b,L)+len+2],
                        ++rt[j-min(b,L)+L],--rt[j-min(b,L)+L+len+1];
                    }
                }
            for(int i=1;i<=n;++i) lt[i]+=lt[i-1],rt[i]+=rt[i-1];
            for(int i=1;i<n;++i) ans+=1LL*rt[i]*lt[i+1];
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Java Web 网络留言板2 JDBC数据源 (连接池技术)
    Java Web 网络留言板3 CommonsDbUtils
    Java Web ConnectionPool (连接池技术)
    Java Web 网络留言板
    Java Web JDBC数据源
    Java Web CommonsUtils (数据库连接方法)
    Servlet 起源
    Hibernate EntityManager
    Hibernate Annotation (Hibernate 注解)
    wpf控件设计时支持(1)
  • 原文地址:https://www.cnblogs.com/FallDream/p/Noi2016d1t1.html
Copyright © 2011-2022 走看看