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\n",(len-1)*(1+len)*len/2-2*solve(len));
    return 0;
}
posted @ 2018-03-03 11:14  AKCqhzdy  阅读(218)  评论(0编辑  收藏  举报