ABC 213 F Common Prefixes题解

题意

给定一个长度为\(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);
}

ABC 213 F Common Prefixes题解

上一篇:前端获取视频的第一帧,作为预览图


下一篇:Win7下使用PB9可能导致的崩溃问题解决方案