• luoguP4248 [AHOI2013]差异


    题意

    考虑式子前面那段其实是((n-1)*frac{n*(n+1)}{2}),因为每个后缀出现了(n-1)次,后缀总长为(frac{n*(n+1)}{2})

    现在考虑后面怎么求:
    (sumlimits_{i=1}^{n}sumlimits_{j=i+1}^nlcp(sa_i,sa_j))

    我们知道后面那个可以转化成(height)数组的(RMQ)问题,于是我们转而考虑每个(height_i)的贡献。

    我们对于每个(i)找到左边第一个小于(height_i)的位置(j),右边第一个小于等于(height_i)的位置(k)(注意条件不同,避免计重),那么(height_i)的贡献即为(height_i*(i-j)*(k-i))

    这个找的过程显然可以单调栈解决,注意(height)(2)开始算(因为([l,r])(height)(l+1)开始,这题所有数据的(height_1)都是(0),所以能过)。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=500010;
    int n,m,top;
    int sa[maxn],rk[maxn],oldrk[maxn],id[maxn],tmpid[maxn],cnt[maxn],height[maxn],sta[maxn],L[maxn],R[maxn];
    char s[maxn];
    inline bool check(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
    inline void sa_build()
    {
        m=300;
        for(int i=1;i<=n;i++)cnt[rk[i]=s[i]]++;
        for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
        for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;
        for(int t=1;t<=n;t<<=1)
        {
            int tot=0;
            for(int i=n-t+1;i<=n;i++)id[++tot]=i;
            for(int i=1;i<=n;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
            tot=0;
            memset(cnt,0,sizeof(cnt));
            for(int i=1;i<=n;i++)cnt[tmpid[i]=rk[id[i]]]++;
            for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
            for(int i=n;i;i--)sa[cnt[tmpid[i]]--]=id[i];
            memcpy(oldrk,rk,sizeof(rk));
            for(int i=1;i<=n;i++)rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
            m=tot;
            if(m==n)break;
        }
        for(int i=1,j=0;i<=n;i++)
        {
            if(j)j--;
            while(s[i+j]==s[sa[rk[i]-1]+j])j++;
            height[rk[i]]=j;
        }
    }
    inline ll calc()
    {
        ll res=0;
        sta[++top]=1;
        for(int i=2;i<=n;i++)
        {
            while(top&&height[sta[top]]>=height[i])R[sta[top--]]=i;
            L[i]=sta[top];
            sta[++top]=i;
        }
        while(top)R[sta[top--]]=n+1;
        for(int i=2;i<=n;i++)res+=1ll*height[i]*(i-L[i])*(R[i]-i);
        return res;
    }
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);
        sa_build();
        printf("%lld
    ",1ll*(n-1)*n*(n+1)/2-2*calc());
        return 0;
    }
    
  • 相关阅读:
    面试干货——年底干货大放送,你准备好了吗?(转)
    JavaScript学习 三、变量、作用域和内存
    JavaScript学习 二、基础
    JavaScript学习 一、简介
    从统计看机器学习常见算法
    [zz]unity 性能优化
    游戏统计指标
    [zz]sql优化相关
    [zz]sql语句执行顺序
    unity 链接
  • 原文地址:https://www.cnblogs.com/nofind/p/12052503.html
Copyright © 2020-2023  润新知