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

    【传送门:BZOJ3238


    简要题意:

      给出一个长度为n的字符串,设Ti为以第i个字符为开头的后缀,lcp(x,y)为x字符串和y字符串的最长公共前缀

      求$$sum_{1<=i<j<=n}len(Ti)+len(Tj)-2*lcp(i,j)$$


    题解:

      后缀数组吧?

      先打个板子

      显然可以先把Σlen(Ti)+len(Tj)直接求出来

      ans=(len-1)*(len+1)*len/2

      接下来处理最长公共前缀和的问题

      先求出height数组,表示字典序排第i-1个的后缀与排第i个的后缀的最长公共前缀

      如果我们要求第i个到第j个的最长公共前缀,就等于min(height[i+1],height[i+2]....height[j])

      我们就用两个单调栈来处理每个height值最多往左右延伸的长度,分别用l[i],r[i]记录

      然后ans-=2*Σ(i-l[i]+1)*(r[i]-i+1)*height[i]

      因为以i往左最多延伸l[i],往右最多延伸r[i]的情况下,包含i的区间有(i-l[i]+1)*(r[i]-i+1)个

      还要注意一个地方,在求的时候,假如相邻的值相等,那么答案就会多算,所以有求r的时候,单调栈的条件要变成<=


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    char a[510000];
    int s[510000];
    int sa1[510000],sa2[510000];
    int Rank[510000];
    int Rsort[510000];
    int tt[510000];
    void getsa(int n,int m)
    {
        memcpy(Rank,s,sizeof(Rank));
        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[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];
            Rank[sa1[1]]=1;p=1;
            for(int i=2;i<=n;i++)
            {
                if(tt[sa1[i]]!=tt[sa1[i-1]]||tt[sa1[i]+ln]!=tt[sa1[i-1]+ln]) p++;
                Rank[sa1[i]]=p;
            }
            ln*=2;m=p;
        }
    }
    LL height[510000];
    int list[510000];
    int l[510000],r[510000];
    int main()
    {
        scanf("%s",a+1);
        int len=strlen(a+1);
        for(int i=1;i<=len;i++) s[i]=a[i]-'a'+1;
        getsa(len,200);
        LL ans=LL(len-1)*LL(len+1)*LL(len)/2;
        height[1]=0;int k=0;
        for(int i=1;i<=len;i++)
        {
            int j=sa1[Rank[i]-1];
            if(k>0) k--;
            while(a[j+k]==a[i+k])k++;
            height[Rank[i]]=k;
        }
        int tail=0;
        for(int i=1;i<=len;i++)
        {
            while(tail!=0&&height[list[tail]]>height[i]) r[list[tail--]]=i-1;
            list[++tail]=i;
        }
        while(tail!=0) r[list[tail--]]=len;
        for(int i=len;i>=1;i--)
        {
            while(tail!=0&&height[list[tail]]>=height[i]) l[list[tail--]]=i+1;
            list[++tail]=i;
        }
        while(tail!=0) l[list[tail--]]=1;
        LL sum=0;
        for(int i=1;i<=len;i++) sum+=LL(i-l[i]+1)*LL(r[i]-i+1)*height[i];
        printf("%lld
    ",ans-sum*2);
        return 0;
    }

     

  • 相关阅读:
    让php更快提供文件下载
    设计模式 03 设计模式分类
    针对配置文件操作 PHP最常用的四个ini函数
    查找算法
    排序算法
    设计模式 01 统一建模语言基础知识
    关于div和css的一些好习惯
    数据结构的基本概念
    HTML特殊转义字符对照列表
    .htaccess 详解
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8548938.html
Copyright © 2011-2022 走看看