[JZOJ5084]子串

来源:互联网 发布:淘宝店铺上传图片尺寸 编辑:程序博客网 时间:2024/06/05 20:55

题目大意

给定一个长度为n的字符串s,你需要计算

i=1nj=1nk=inl=jnLCP(si..k,sj..l)

答案对998244353取模。

1n500000


题目分析

s构造后缀数组,然后考虑从大到小枚举LCP的长度,然后每次答案加上LCP长度大于等于该值的子串个数。
一开始后缀数组的每一个位置都是孤立的一个块,随着LCP长度的减少我们开始合并相邻的一些块。显然我们只需要记录一个块内的后缀长度和以及后缀个数就可以很方便地计算答案,这个信息也是可以合并的。
时间复杂度O(nlogn)


代码实现

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int P=998244353;const int N=500050;int SA[N],rk[N],Ws[N],Wv[N],x[N],y[N],height[N],fa[N],size[N],sum[N],pos[N],rank[N],p[N];char s[N];int n,ans,cur1,cur2,cur3;int sqr(int x){return 1ll*x*x%P;}bool comp1(int x,int y){return height[x]<height[y];}bool comp2(int x,int y){return n-SA[x]<n-SA[y];}bool cmp(int *a,int x,int y,int l){return x+l>=n||y+l>=n||a[x]!=a[y]||a[x+l]!=a[y+l];}void DA(){    int i,j,p,l,mx;    for (i=0,mx=0;i<n;++i) mx=max(mx,Wv[i]=s[i]-'a');    for (i=0;i<=mx;++i) Ws[i]=0;    for (i=0;i<n;++i) ++Ws[Wv[i]];    for (i=1;i<=mx;++i) Ws[i]+=Ws[i-1];    for (i=n-1;i>=0;--i) SA[--Ws[Wv[i]]]=i;    for (x[SA[0]]=p=0,i=1;i<n;++i) x[SA[i]]=p+=s[SA[i]]!=s[SA[i-1]];    for (l=1;l<=n&&p!=n-1;l<<=1)    {        for (p=0,i=n-l;i<n;++i) y[p++]=i;        for (i=0;i<n;++i) if (SA[i]>=l) y[p++]=SA[i]-l;        for (mx=0,i=0;i<n;++i) mx=max(mx,Wv[i]=x[y[i]]);        for (i=0;i<=mx;++i) Ws[i]=0;        for (i=0;i<n;++i) ++Ws[Wv[i]];        for (i=1;i<=mx;++i) Ws[i]+=Ws[i-1];        for (i=n-1;i>=0;--i) SA[--Ws[Wv[i]]]=y[i];        for (i=0;i<n;++i) y[i]=x[i],x[i]=0;        for (x[SA[0]]=p=0,i=1;i<n;++i) x[SA[i]]=p+=cmp(y,SA[i],SA[i-1],l);    }    for (i=0;i<n;++i) rank[SA[i]]=i;}void getheight(){    for (int i=0,h=0;i<n;++i,h=max(0,h-1))    {        if (rank[i]) for (int k=SA[rank[i]-1];i+h<n&&k+h<n&&s[i+h]==s[k+h];++h);        height[rank[i]]=h;    }}int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}void merge(int x,int y){    x=getfather(x),y=getfather(y);    if (rank[x]<rank[y]) swap(x,y);    fa[y]=x,rank[x]+=rank[x]==rank[y];    cur1=(cur1-sqr(sum[x])+P)%P,cur2=(cur2-1ll*sum[x]*size[x]%P+P)%P,cur3=(cur3-sqr(size[x])+P)%P;    cur1=(cur1-sqr(sum[y])+P)%P,cur2=(cur2-1ll*sum[y]*size[y]%P+P)%P,cur3=(cur3-sqr(size[y])+P)%P;    (sum[x]+=sum[y])%=P,size[x]+=size[y];    (cur1+=sqr(sum[x]))%=P,(cur2+=1ll*sum[x]*size[x]%P)%=P,(cur3+=sqr(size[x]))%=P;}void calc(){    for (int i=0;i<n;++i) fa[i]=i,rank[i]=0,size[i]=0,sum[i]=0,pos[i]=i,p[i]=i;    sort(pos,pos+n,comp1),sort(p,p+n,comp2);    cur1=cur2=cur3=0;    for (int i=0;i<n;++i) (cur1+=sqr(sum[i]))%=P,(cur2+=1ll*sum[i]*size[i]%P)%=P,(cur3+=sqr(size[i]))%=P;    for (int i=n,cur=n-1,ptr=n-1;i>=1;--i)    {        for (;ptr>=0&&n-SA[p[ptr]]==i;--ptr)        {            int x=getfather(p[ptr]);            cur1=(cur1-sqr(sum[x])+P)%P,cur2=(cur2-1ll*sum[x]*size[x]%P+P)%P,cur3=(cur3-sqr(size[x])+P)%P;            (sum[x]+=n-SA[p[ptr]])%=P,++size[x];            (cur1+=sqr(sum[x]))%=P,(cur2+=1ll*sum[x]*size[x]%P)%=P,(cur3+=sqr(size[x]))%=P;        }        for (;cur>=0&&height[pos[cur]]==i;--cur)        {            int x=pos[cur];            if (x) merge(x-1,x);        }        (ans+=(cur1+1ll*cur3*sqr(i-1)%P-2ll*cur2*(i-1)%P+P)%P)%=P;    }}int main(){    freopen("substring.in","r",stdin),freopen("substring.out","w",stdout);    scanf("%s",s),n=strlen(s);    DA(),getheight(),calc();    printf("%d\n",ans);    fclose(stdin),fclose(stdout);    return 0;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 平板开关键坏了怎么办 平板电脑电池坏了怎么办 平板电脑充电口坏了怎么办 平板电脑系统坏了怎么办 平板电脑充电器坏了怎么办 平板电脑触摸屏坏了怎么办 平板电脑关不了机怎么办 平板电脑触摸屏没反应怎么办 平板电脑声音太小怎么办 平板电脑频碎了怎么办? 淘宝直播展示频道排后怎么办 网店头像改不了怎么办 被骗了7500追不回来怎么办 steam中国版原来的游戏怎么办 老公买驾照被骗妻子应该怎么办 被淘密码骗了怎么办 逛街手机没电了怎么办 电脑登入密码忘了怎么办 晚上睡不好觉经常做梦怎么办 开淘宝店开始零销量怎么办 淘宝店开直通车后销量怎么办 淘宝直播一开始直播没人该怎么办 淘宝店铺访客数据下滑怎么办 2个ctrl键都失灵怎么办 淘宝上搜索不到很久以前订单怎么办 关键词找不到了是不是被降权怎么办 购买小程序关键词想退款怎么办? 浏览器审查元素不拆分关键词怎么办 拼多多商品想重新编辑怎么办 新开店铺没有销量怎么办 新开的店铺没有销量怎么办 淘宝的商品权重下降是怎么办 360n5手机耗电快怎么办 怪兽充电宝丢了怎么办 有已处置的评价怎么办 淘宝降权了怎么办2018 使用虚假广告词被工商查到怎么办 为什么手机淘宝店关注不了怎么办 淘宝买东西付钱后卖家不发货怎么办 微信销售群没人买东西怎么办 淘宝想开2个店铺怎么办