[bzoj3238][Ahoi2013]差异
来自FallDream的博客,未经允许,请勿转载,谢谢。
n<=500000
我只会yy一个奇怪做法.....
因为lcp是后缀数组中一段区间的Height的最小值,所以考虑先求出Height数组,然后对于每一位,二分它能成为最小值的区间并计算答案。
当然,也可以直接建出小顶的笛卡尔树,满足堆性质的同时顺序不变,这样笛卡尔树上每个节点的贡献就是2*h[x]*(size(l[x])+1)*(size(r[x])+1)
怎么感觉我的后缀数组特别慢啊?
后缀数组+二分
#include<iostream> #include<cstdio> #include<cstring> #define INF 2000000000 #define MN 500000 #define MD 19 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } long long ans=0; char st[MN*2+5]; int n,v[MN+5],sa[2][MN+5],P[MN+5],rk[2][MN+5],k,p=1,q=0,h[MN+5],f[MD+1][MN+5],g[MD+1][MN+5],Fa[MD+1][MN+5],fa[MD+1][MN+5]; void Calc(int*sa,int*rk,int*SA,int*Rk) { for(int i=1;i<=n;i++) v[rk[sa[i]]]=i; for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i; for(int i=1;i<=n;i++) Rk[SA[i]]=Rk[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); } void GetH(int*sa,int*rk) { for(int i=1,k=0;i<=n;h[rk[i++]]=k,k=max(0,k-1)) for(int j=sa[rk[i]-1];st[j+k]==st[i+k];++k); } inline int Calc(int l,int r) { if(l>r) return -1; int len=P[r-l+1]; return min(f[len][l],g[len][r]); } int GetLeft(int l,int r,int x) { int mid,ans=0; while(l<=r) { mid=l+r>>1; if(Calc(mid,x)>=h[x]) ans=mid,r=mid-1; else l=mid+1; } return ans; } int GetRight(int l,int r,int x) { int mid,ans=0; while(l<=r) { mid=l+r>>1; if(Calc(x+1,mid)>h[x]) ans=mid,l=mid+1; else r=mid-1; } return ans; } int main() { scanf("%s",st+1);n=strlen(st+1); ans=1LL*n*(n+1)/2*(n-1); for(int i=1;i<=n;i++) ++v[st[i]-'a']; for(int i=1;i<26;i++) v[i]+=v[i-1]; for(int i=1;i<=n;i++) sa[0][v[st[i]-'a']--]=i; for(int i=1;i<=n;i++) rk[0][sa[0][i]]=rk[0][sa[0][i-1]]+(st[sa[0][i]]!=st[sa[0][i-1]]); for(k=1;k<n;k<<=1) { Calc(sa[q],rk[q],sa[p],rk[p]); swap(p,q); } GetH(sa[q],rk[q]); h[1]=INF; memset(g,42,sizeof(g));memset(f,42,sizeof(f)); for(int i=1;i<=n;i++) g[0][i]=f[0][i]=h[i],fa[0][i]=i+1,Fa[0][i]=i-1; fa[0][n]=0;P[0]=-1; for(int i=1;i<=n;i++) P[i]=P[i>>1]+1; for(int i=1;i<=MD;i++) for(int j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]], f[i][j]=min(f[i-1][j],f[i-1][fa[i-1][j]]), Fa[i][j]=Fa[i-1][Fa[i-1][j]], g[i][j]=min(g[i-1][j],g[i-1][Fa[i-1][j]]); for(int i=2;i<=n;i++) { int lt,rt; (lt=GetLeft(2,i-1,i))?0:lt=i; (rt=GetRight(i+1,n,i))?0:rt=i; ans-=2LL*(i-lt+1)*(rt-i+1)*h[i]; } printf("%lld\n",ans); return 0; }
后缀数组+笛卡尔树
#include<iostream> #include<cstdio> #include<cstring> #define MN 500000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } long long ans=0; char st[MN*2+5]; int n,v[MN+5],sa[2][MN+5],rk[2][MN+5],k,p=1,q=0,h[MN+5],Q[MN+5],top=0,size[MN+5],l[MN+5],r[MN+5]; void Calc(int*sa,int*rk,int*SA,int*Rk) { for(int i=1;i<=n;i++) v[rk[sa[i]]]=i; for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i; for(int i=1;i<=n;i++) Rk[SA[i]]=Rk[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); } void GetH(int*sa,int*rk) { for(int i=1,k=0;i<=n;h[rk[i++]]=k,k=max(0,k-1)) if(rk[i]!=1) for(int j=sa[rk[i]-1];st[j+k]==st[i+k];++k); } int build() { int last; for(int i=2;i<=n;i++) { last=0; while(top&&h[Q[top]]>=h[i]) last=Q[top--]; if(top) r[Q[top]]=i; Q[++top]=i; l[Q[top]]=last; } for(;top>1;--top) r[Q[top-1]]=Q[top]; return Q[1]; } void dfs(int x) { if(l[x]) dfs(l[x]); if(r[x]) dfs(r[x]); size[x]=size[l[x]]+size[r[x]]+1; ans-=2LL*h[x]*(size[l[x]]+1)*(size[r[x]]+1); } int main() { scanf("%s",st+1);n=strlen(st+1); ans=1LL*n*(n+1)/2*(n-1); for(int i=1;i<=n;i++) ++v[st[i]-'a']; for(int i=1;i<26;i++) v[i]+=v[i-1]; for(int i=1;i<=n;i++) sa[0][v[st[i]-'a']--]=i; for(int i=1;i<=n;i++) rk[0][sa[0][i]]=rk[0][sa[0][i-1]]+(st[sa[0][i]]!=st[sa[0][i-1]]); for(k=1;k<n;k<<=1) { Calc(sa[q],rk[q],sa[p],rk[p]); swap(p,q); } GetH(sa[q],rk[q]); int rt=build(); dfs(rt); printf("%lld\n",ans); return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream