Codeforces 452E Three strings 字符串 SAM

Posted zhouzhendong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 452E Three strings 字符串 SAM相关的知识,希望对你有一定的参考价值。

原文链接https://www.cnblogs.com/zhouzhendong/p/CF542E.html

题目传送门 - CF452E

题意

  给定三个字符串 $s1,s2,s3$ ,对于所有 $Lin{1,2,cdots,min(|s1|,|s2|,|s3|)}$ ,输出 $f(L)$ 。

  其中 $f(L)$ 表示满足 $s_k[i_k,cdots,i_k+L-1]$ 全部相同的 $i_1,i_2,i_3$ 的个数。

  答案对 $10^9+7$ 取模。

  $|s1|+|s2|+|s3|leq 3 imes 10^5$

题解

  第二次写广义后缀自动机,居然又只写了 20 分钟??然而没有看到取模,以及一个取模上面的傻逼错误续了我 15 分钟。

  把三个串全部扔进广义后缀自动机里面。

  对于每一个状态,分别算出属于这三个串的 right 集合大小。

  然后对于每一个节点,方案总数就是 $prod_{k=0}^{2}right_{i,k}$ ,影响的长度范围是 $( m{Max(father),Max(i)}]$ ,相当于区间加,直接差分一下就可以了。

  最后回答的时候前缀和一下就好了。注意取模。

代码

#include <bits/stdc++.h>
#define right __fjw82
using namespace std;
const int N=300005,S=N*2,mod=1e9+7;
char s[N];
int n=1e9,in[S],q[S],ans[N],right[S][3],head,tail;
int root,size;
struct SAM{
	int Next[26],fa,Max;
}t[N<<1];
void init(){
	memset(t,0,sizeof t);
	root=size=1;
	t[0].Max=-1;
	for (int i=0;i<26;i++)
		t[0].Next[i]=1;
}
int extend(int p,int c){
	if (t[p].Next[c]&&t[p].Max+1==t[t[p].Next[c]].Max)
		return t[p].Next[c];
	int np=++size,q,nq;
	t[np].Max=t[p].Max+1;
	for (;!t[p].Next[c];p=t[p].fa)
		t[p].Next[c]=np;
	q=t[p].Next[c];
	if (t[p].Max+1==t[q].Max)
		t[np].fa=q;
	else {
		nq=++size;
		t[nq]=t[q],t[nq].Max=t[p].Max+1;
		t[q].fa=t[np].fa=nq;
		for (;t[p].Next[c]==q;p=t[p].fa)
			t[p].Next[c]=nq;
	}
	return np;
}
int main(){
	init();
	for (int i=0,now;i<3;i++){
		scanf("%s",s+1);
		n=min(n,now=strlen(s+1));
		for (int j=1,p=root;j<=now;j++)
			right[p=extend(p,s[j]-‘a‘)][i]++;
	}
	for (int i=2;i<=size;i++)
		in[t[i].fa]++;
	head=tail=0;
	for (int i=2;i<=size;i++)
		if (in[i]==0)
			q[++tail]=i;
	while (head<tail){
		int x=q[++head];
		for (int i=0;i<3;i++)
			right[t[x].fa][i]+=right[x][i];
		in[t[x].fa]--;
		if (t[x].fa>1&&!in[t[x].fa])
			q[++tail]=t[x].fa;
	}
	memset(ans,0,sizeof ans);
	for (int i=2;i<=size;i++){
		int add=1LL*right[i][0]*right[i][1]*right[i][2]%mod;
		(ans[t[t[i].fa].Max+1]+=add)%=mod;
		(ans[t[i].Max+1]+=mod-add)%=mod;
	}
	for (int i=1;i<=n;i++){
		ans[i]=(ans[i]+ans[i-1])%mod;
		printf("%d ",ans[i]);
	}
	return 0;
}

  

以上是关于Codeforces 452E Three strings 字符串 SAM的主要内容,如果未能解决你的问题,请参考以下文章

codeforces-1335-E Three Blocks Palindrome

codeforces 653A A. Bear and Three Balls(水题)

Divide by Three CodeForces - 792C

题解[CodeForces1154A]Restoring Three Numbers

Codeforces Round #485 (Div. 2) C. Three displays

CodeForces - 1131D(Three Integers)