P4248 [AHOI2013]差异 解题报告

P4248 [AHOI2013]差异

题目描述

给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀。求

\[\displaystyle \sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j) \]

其中,\(\text{len}(a)\)表示字符串 \(a\) 的长度,\(\text{lcp}(a,b)\) 表示字符串 \(a\) 和字符串 \(b\) 的最长公共前缀。

输入输出格式

输入格式:

一行,一个字符串 \(S\)

输出格式:

一行,一个整数,表示所求值。

说明

对于 \(100\%\) 的数据,保证 \(2\leqslant n\leqslant 500000\),且均为小写字母。


思路:先用SA求出height数组,然后从最小的开始删并维护联通性,发现用可以用单调栈处理这个过程。

我人太傻一开始求错了算法迷了好久...


Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
const int N=5e5+10;
int sa[N],Rank[N],tax[N],sec[N],height[N],sta[N],L[N],R[N],tot,n,m;
char s[N];
void Rsort()
{
    for(int i=1;i<=m;i++) tax[i]=0;
    for(int i=1;i<=n;i++) ++tax[Rank[i]];
    for(int i=2;i<=m;i++) tax[i]+=tax[i-1];
    for(int i=n;i;i--) sa[tax[Rank[sec[i]]]--]=sec[i];
}
bool cmp(int x,int y,int l){return sec[x]==sec[y]&&sec[x+l]==sec[y+l];}
void SuffixSort()
{
    scanf("%s",s+1);n=strlen(s+1);
    for(int i=1;i<=n;i++) Rank[i]=s[i]+1-'a',sec[i]=i;
    m=26;Rsort();
    for(int p=0,w=1;p<n;w<<=1,m=p)
    {
        p=0;for(int i=n-w+1;i<=n;i++) sec[++p]=i;
        for(int i=1;i<=n;i++) if(sa[i]>w) sec[++p]=sa[i]-w;
        Rsort();std::swap(Rank,sec);
        Rank[sa[1]]=p=1;
        for(int i=2;i<=n;i++) Rank[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
    }
    for(int p=0,i=1;i<=n;height[Rank[i++]-1]=p)
        for(p=p?p-1:p;s[i+p]==s[sa[Rank[i]-1]+p];++p);
}
int main()
{
    SuffixSort();
    for(int i=1;i<n;i++)
    {
        while(tot&&height[sta[tot]]>=height[i]) --tot;
        L[i]=sta[tot]+1;
        sta[++tot]=i;
    }
    sta[tot=0]=n;
    for(int i=n-1;i;i--)
    {
        while(tot&&height[sta[tot]]>height[i]) --tot;
        R[i]=sta[tot]-1;
        sta[++tot]=i;
    }
    ll ans=1ll*(n+1)*(n-1)*n/2;
    for(int i=1;i<n;i++)
        ans-=2ll*(R[i]-i+1)*(i-L[i]+1)*height[i];
    printf("%lld\n",ans);
    return 0;
}

2018.12.15

posted @ 2018-12-15 14:50  露迭月  阅读(151)  评论(0编辑  收藏  举报