• bzoj3238: [Ahoi2013]差异


    发现我做题都是一眼秒算法,然后就不知道怎么做了。

    好的这次一眼就是后缀数组了。

    然后这个式子前面的可以O(1)公式搞定,其实问的就是sigema(LCP(Ti,Tj))

    然后先写了个暴力,就大概长这样:

    int pos[510000],f[510000],ff[510000];
    int solve(int n)
    {
        int ans=0;
        memset(f,0,sizeof(f));
        for(int i=1;i<n;i++)
        {
            if(f[i]!=0)f[i]=f[pos[i]]-ff[i];
            else
            {
                int mi=2147483647;
                for(int j=i+1;j<=n;j++)
                {
                    if(height[j]<=mi)
                    {
                        mi=height[j];
                        if(j-1!=i)
                        {
                            pos[j-1]=i;
                            ff[i]=f[i];
                        }
                    }
                    f[i]+=mi;
                }
            }
            ans+=f[i];
        }
        return ans;
    }

    可以发现mi是递减的嘛,然后对于一个height值,它所能影响的区间就是前一个比他大值的位置+1 ~ 后一个比他大的位置-1,然后就是两个单调栈搞一搞了。

    有个有趣的问题,就是假如相邻的值相等,那么答案就会多算,所以要变成<=

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    int a[510000],tt[510000];
    int sa1[510000],sa2[510000],Rank[510000];
    int Rsort[510000];
    void get_sa(LL n,int m)
    {
        for(int i=1;i<=n;i++)Rank[i]=a[i];
        
        memset(Rsort,0,sizeof(Rsort));
        for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
        for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
        for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i;
        
        int ln=1,p=0;
        while(p<n)
        {
            int k=0;for(int i=n-ln+1;i<=n;i++)sa2[++k]=i;
            for(int i=1;i<=n;i++)
                if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln;
                
            memset(Rsort,0,sizeof(Rsort));
            for(int i=1;i<=n;i++)Rsort[Rank[sa2[i]]]++;
            for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
            for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];
            
            for(int i=1;i<=n;i++)tt[i]=Rank[i];
            
            p=1;Rank[sa1[1]]=1;
            for(int i=2;i<=n;i++)
            {
                if(tt[sa1[i-1]]!=tt[sa1[i]]||tt[sa1[i-1]+ln]!=tt[sa1[i]+ln])p++;
                Rank[sa1[i]]=p;
            }
            ln*=2;m=p;
        }
    }
    LL height[510000];
    void get_he(int n)
    {
        int j;LL h=0;
        for(int i=1;i<=n;i++)
        {
            j=sa1[Rank[i]-1];
            if(h!=0)h--;
            while(a[i+h]==a[j+h])h++;
            height[Rank[i]]=h;
        }
    }
    
    //--------------sa-------------
    
    int top,sta[510000];
    LL l[510000],r[510000];
    LL solve(LL n)
    {
        top=0;
        
        for(int i=1;i<=n;i++)
        {
            while(top>0&&height[i]<height[sta[top]])
                r[sta[top]]=i-1, top--;
            sta[++top]=i;
        }
        while(top>0) r[sta[top]]=n, top--;
        for(int i=n;i>=1;i--)
        {
            while(top>0&&height[i]<=height[sta[top]])
                l[sta[top]]=i+1, top--;
            sta[++top]=i;
        }
        while(top>0) l[sta[top]]=1, top--;
        
        LL ans=0;
        for(int i=1;i<=n;i++)
            ans+=(i-l[i]+1)*(r[i]-i+1)*height[i];
        return ans;
    }
    char ss[510000];
    int main()
    {
        scanf("%s",ss+1);LL len=strlen(ss+1);
        for(int i=1;i<=len;i++)a[i]=ss[i]-'a'+1;
        
        get_sa(len,200);get_he(len);
        
        
        printf("%lld
    ",(len-1)*(1+len)*len/2-2*solve(len));
        return 0;
    }
  • 相关阅读:
    linux信号
    APM浅析
    Jackson高并发情况下,产生阻塞
    [转]slf4j 与log4j 日志管理
    2015-09-27 git学习
    MySQL学习笔记-锁相关话题
    MySQL学习笔记-MySQL数据库优化实践[转]
    MySQL学习笔记-事务相关话题
    几个关于网站架构和性能的问题(我在知乎上的问答)
    MySQL学习笔记-数据库文件
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8496072.html
Copyright © 2020-2023  润新知