ABC 213 F Common Prefixes題解
阿新 • • 發佈:2021-08-10
題意
給定一個長度為\(n\)的字串\(s\),設對於兩字串\(x\),\(y\),\(f(x,y)=\max\{k|1\le k\le \min(|x|,|y|)且\forall i\in [1,k]\cap N^*,x_i=y_i\}\)。
設\(S_i={s_is_{i+1}\cdots s_n}\)。對於每一個\(k\in [1,n]\cap N^*\),求\(\sum_{i=1}^nf(S_i,S_k)\)。
思路
首先預處理出\(height\)陣列,\(h[i]=lcp(suf_{sa_i},suf_{sa_{i-1}})\)。
有結論:\(lcp(suf_i,suf_j)(rnk_i<rnk_j)=\min_{k=rnk_i+1}^{rnk_j}h_k\)
此時,題目轉換為:給出一長度為\(n\)的序列\(a_1,a_2,\cdots,a_n\),要求對每一個\(i\)求出\(\sum_{i=1}^n\min_{k=\min(i,j)}^{\max(i,j)}a_k\)。
這個問題可以用單調棧輕鬆求出。
總時間複雜度:\(O(n+SA(n))\),其中\(SA(n)\)表示求字尾陣列所需要的時間。
程式碼
using namespace std; typedef long long ll; const int mod=998244353; int fir[2000005],rnk[2000005],sa[2000005],sec[2000005],s[2000005],h[2000005]; int st[2000005],top; ll val[2000005],ans[2000005]; char str[2000005]; void MakeSA(int n,int m){ int *x=rnk,*y=sec; for(int i=1;i<=n;i++)s[x[i]=str[i]-'a'+1]++; for(int i=1;i<=m;i++)s[i]+=s[i-1]; for(int i=n;i;i--)sa[s[x[i]]--]=i; for(int j=1,p=0;p<n?(p=0,1):0;j<<=1,m=p){ for(int i=n-j+1;i<=n;i++)y[++p]=i; for(int i=1;i<=n;i++)if(sa[i]>j)y[++p]=sa[i]-j; for(int i=1;i<=m;i++)s[i]=0; for(int i=1;i<=n;i++)s[fir[i]=x[y[i]]]++; for(int i=1;i<=m;i++)s[i]+=s[i-1]; for(int i=n;i;i--)sa[s[fir[i]]--]=y[i]; swap(x,y),x[sa[p=1]]=1; for(int i=2;i<=n;i++)x[sa[i]]=(p+=(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j])); } for(int i=1;i<=n;i++)rnk[sa[i]]=i; for(int i=1,j=0;i<=n;i++){ if(rnk[i]==1)h[rnk[i]]=0; else { j=max(j-1,0); while(str[i+j]==str[sa[rnk[i]-1]+j])j++; h[rnk[i]]=j; } } top=0,st[0]=1; for(int i=2;i<=n;i++){ while(top&&h[st[top]]>=h[i])top--; st[++top]=i,val[top]=val[top-1]+1ll*(i-st[top-1])*h[i]; ans[i]+=val[top]; } top=0,st[0]=n+1; for(int i=n;i>=2;i--){ while(top&&h[st[top]]>=h[i])top--; st[++top]=i,val[top]=val[top-1]+1ll*(st[top-1]-i)*h[i]; ans[i-1]+=val[top]; } for(int i=1;i<=n;i++)printf("%lld\n",ans[rnk[i]]+(n-i+1)); } int main(){ int n; cin>>n>>str+1; MakeSA(n,26); }
本文來自部落格園,作者:jpy_cpp,轉載請註明原文連結:https://www.cnblogs.com/jpy-cpp/p/15122798.html