zoukankan      html  css  js  c++  java
  • [bzoj3238][Ahoi2013]差异

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


    n<=500000

    我只会yy一个奇怪做法.....

    因为lcp是后缀数组中一段区间的Height的最小值,所以考虑先求出Height数组,然后对于每一位,二分它能成为最小值的区间并计算答案。

    当然,也可以直接建出小顶的笛卡尔树,满足堆性质的同时顺序不变,这样笛卡尔树上每个节点的贡献就是2*h[x]*(size(l[x])+1)*(size(r[x])+1)

    怎么感觉我的后缀数组特别慢啊?

    后缀数组+二分

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define INF 2000000000
    #define MN 500000
    #define MD 19
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    long long ans=0;
    char st[MN*2+5];
    int n,v[MN+5],sa[2][MN+5],P[MN+5],rk[2][MN+5],k,p=1,q=0,h[MN+5],f[MD+1][MN+5],g[MD+1][MN+5],Fa[MD+1][MN+5],fa[MD+1][MN+5];
    
    void Calc(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*sa,int*rk)
    {
        for(int i=1,k=0;i<=n;h[rk[i++]]=k,k=max(0,k-1))
            for(int j=sa[rk[i]-1];st[j+k]==st[i+k];++k);    
    }
    
    inline int Calc(int l,int r)
    {    
        if(l>r) return -1;
        int len=P[r-l+1];    
        return min(f[len][l],g[len][r]);    
    }
    
    int GetLeft(int l,int r,int x)
    {
        int mid,ans=0;    
        while(l<=r)
        {
            mid=l+r>>1;
            if(Calc(mid,x)>=h[x]) ans=mid,r=mid-1;
            else l=mid+1;    
        }
        return ans;
    }
    
    int GetRight(int l,int r,int x)
    {
        int mid,ans=0;
        while(l<=r)
        {
            mid=l+r>>1;
            if(Calc(x+1,mid)>h[x]) ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    
    int main()
    {
        scanf("%s",st+1);n=strlen(st+1);
        ans=1LL*n*(n+1)/2*(n-1);
        for(int i=1;i<=n;i++) ++v[st[i]-'a'];
        for(int i=1;i<26;i++) v[i]+=v[i-1];
        for(int i=1;i<=n;i++) sa[0][v[st[i]-'a']--]=i; 
        for(int i=1;i<=n;i++) rk[0][sa[0][i]]=rk[0][sa[0][i-1]]+(st[sa[0][i]]!=st[sa[0][i-1]]);
        for(k=1;k<n;k<<=1) 
        {
            Calc(sa[q],rk[q],sa[p],rk[p]);
            swap(p,q);
        }
        GetH(sa[q],rk[q]); h[1]=INF; 
        memset(g,42,sizeof(g));memset(f,42,sizeof(f));
        for(int i=1;i<=n;i++) g[0][i]=f[0][i]=h[i],fa[0][i]=i+1,Fa[0][i]=i-1;
        fa[0][n]=0;P[0]=-1;
        for(int i=1;i<=n;i++) P[i]=P[i>>1]+1;
        for(int i=1;i<=MD;i++)
            for(int j=1;j<=n;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]]),
                Fa[i][j]=Fa[i-1][Fa[i-1][j]],
                g[i][j]=min(g[i-1][j],g[i-1][Fa[i-1][j]]);
        for(int i=2;i<=n;i++)
        {
            int lt,rt;
            (lt=GetLeft(2,i-1,i))?0:lt=i;
            (rt=GetRight(i+1,n,i))?0:rt=i;
            ans-=2LL*(i-lt+1)*(rt-i+1)*h[i];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    后缀数组+笛卡尔树

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 500000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    long long ans=0;
    char st[MN*2+5];
    int n,v[MN+5],sa[2][MN+5],rk[2][MN+5],k,p=1,q=0,h[MN+5],Q[MN+5],top=0,size[MN+5],l[MN+5],r[MN+5];
    
    void Calc(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*sa,int*rk)
    {
        for(int i=1,k=0;i<=n;h[rk[i++]]=k,k=max(0,k-1)) if(rk[i]!=1)
            for(int j=sa[rk[i]-1];st[j+k]==st[i+k];++k);    
    }
    
    int build()
    {
        int last;
        for(int i=2;i<=n;i++)
        {
            last=0;
            while(top&&h[Q[top]]>=h[i]) last=Q[top--];
            if(top) r[Q[top]]=i;
            Q[++top]=i;
            l[Q[top]]=last; 
        }
        for(;top>1;--top) r[Q[top-1]]=Q[top];
        return Q[1];
    }
    
    void dfs(int x)
    {
        if(l[x]) dfs(l[x]);
        if(r[x]) dfs(r[x]);
        size[x]=size[l[x]]+size[r[x]]+1;
        ans-=2LL*h[x]*(size[l[x]]+1)*(size[r[x]]+1); 
    }
    
    int main()
    {
        scanf("%s",st+1);n=strlen(st+1);
        ans=1LL*n*(n+1)/2*(n-1);
        for(int i=1;i<=n;i++) ++v[st[i]-'a'];
        for(int i=1;i<26;i++) v[i]+=v[i-1];
        for(int i=1;i<=n;i++) sa[0][v[st[i]-'a']--]=i; 
        for(int i=1;i<=n;i++) rk[0][sa[0][i]]=rk[0][sa[0][i-1]]+(st[sa[0][i]]!=st[sa[0][i-1]]);
        for(k=1;k<n;k<<=1) 
        {
            Calc(sa[q],rk[q],sa[p],rk[p]);
            swap(p,q);
        }
        GetH(sa[q],rk[q]); 
        int rt=build();
        dfs(rt);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    条件概率和链式法则 conditional probability & chain rule
    如何训练一个神经网络?
    高斯贝叶斯分类器
    LDA
    机器学习中的数学-线性判别分析(LDA)
    理解矩阵
    pca数学原理(转)
    SVM入门
    Top 10 Machine Learning Algorithms For Beginners
    vfp
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3238.html
Copyright © 2011-2022 走看看