【jzoj5084】【GDOI2017第四轮模拟day1】【子串】【后缀数组】

来源:互联网 发布:mac 编译安装php fpm 编辑:程序博客网 时间:2024/06/09 23:55

题目大意

YJC最近写了一篇关于子串的论文。CJY看他那么喜欢子串,决定出一道题考考他。

CJY给出了一个字符串s,令s[l~r]表示s中区间[l,r]构成的子串,下标从1开始。他向YJC提出了许多询问,每次询问给了四个数i,j,k,l,求LCP(s[i~k],s[j~l]),即每次询问两个子串的最长公共前缀。YJC很轻松地解决了这个问题。CJY表示很不爽,于是他改变了一下问题,让YJC求所有合法的询问的答案的和,即设n=|S|,求这里写图片描述

。YJC发现现在自己不会做了,于是他来向你求助。因为这个数可能很大,你只需要告诉他答案mod 998244353的值即可。

解题思路

先做一遍sa,对height前后做一次单调栈,分别是递增和不递减,求出点的数量和sa和,推出公式后可以直接得解,先把含的式子求出来,用等差数列求和公式前缀平方和公式求和即可。注意把答案乘二后加上自己乘自己的情况。

code

#include<cstdio>#include<cstring>#include<algorithm>#define LL long long#define fo(i,j,k) for(LL i=j;i<=k;i++)#define fd(i,j,k) for(LL i=j;i>=k;i--)using namespace std;LL const mn=5*1e5+9,mo=998244353;LL n,m,a[2][mn],sa[mn],cnt[mn],h[mn],st[mn],f[mn],g[mn],suml[mn],sizel[mn];LL *rank=a[0],*ord=a[1];char s[mn];void sort(){    fo(i,1,m)cnt[i]=0;    fo(i,1,n)cnt[rank[i]]++;    fo(i,1,n)cnt[i]+=cnt[i-1];    fd(i,n,1)sa[cnt[rank[ord[i]]]--]=ord[i];}LL diff(LL x,LL y,LL z){    return (ord[x]!=ord[y])||(ord[x+z]!=ord[y+z]);}int main(){    //freopen("substring.in","r",stdin);    //freopen("substring.out","w",stdout);    freopen("d.in","r",stdin);    freopen("d.out","w",stdout);    scanf("%s",s+1);n=strlen(s+1);    fo(i,1,n)rank[i]=s[i]-'a'+1,ord[i]=i;m=26;    sort();    for(LL w=1,p=0;p!=n;w<<=1){        p=0;fo(i,n-w+1,n)ord[++p]=i;        fo(i,1,n)if(sa[i]>w)ord[++p]=sa[i]-w;        sort();swap(rank,ord);rank[sa[1]]=p=1;        fo(i,2,n)rank[sa[i]]=p+=diff(sa[i],sa[i-1],w);        m=p;    }    for(LL i=1,j,p=0;i<=n;h[rank[i]]=p,i++)        for(j=sa[rank[i]-1],p=(p)?p-1:p;s[i+p]==s[j+p];p++);    LL ans=0;    fo(i,2,n){        LL tmp=0,tmp2=0;        while(st[0]&&(st[st[0]]>h[i]))tmp+=f[st[0]],tmp2+=g[st[0]],st[0]--;        st[++st[0]]=h[i];        suml[i]=f[st[0]]=(tmp+sa[i-1])%mo;        sizel[i]=g[st[0]]=tmp2+1;    }    st[0]=0;    fd(i,n,2){        LL tmp=0,tmp2=0;        while(st[0]&&(st[st[0]]>=h[i]))tmp+=f[st[0]],tmp2+=g[st[0]],st[0]--;        st[++st[0]]=h[i];        f[st[0]]=(tmp+sa[i])%mo;        g[st[0]]=tmp2+1;        LL l=h[i],sumr=f[st[0]],sizer=g[st[0]];        ans=(ans+((l*(l+1)/2-l*(l+1)*(2*l+1)/6)/2+l*(n+1-l)*(n+1-l)-l*l*(l+1)/2)%mo*(sizel[i]*sizer%mo)            -(l*(n+1-l)%mo)*((suml[i]*sizer+sumr*sizel[i])%mo)+(l*(l+1)/2%mo)*((((n+1)*sizel[i]-suml[i])*sizer+((n+1)*sizer-sumr)*sizel[i])%mo)            +l*suml[i]%mo*sumr)%mo;    }    ans<<=1;    fo(i,1,n)ans=(ans+(i*(i+1)/2-i*(i+1)*(2*i+1)/6)/2+i*i*(i+1)/2)%mo;    printf("%lld",ans);    return 0;}
0 0
原创粉丝点击