BZOJ4566 [Haoi2016]找相同字符 字符串 SAM

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

题目传送门 - BZOJ4566

题意

  给定两个字符串 $s1$ 和 $s2$ ,问有多少 $a,b,c,d$ 满足 $s1[a\cdots b] = s2[c\cdots d]$ 。

  $|s1|,|s2|\leq 200000$

题解

  建个广义 SAM ,然后统计一下。

  模板题。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005*4;
struct SAM{
	int Next[26],fa,Max;
}t[N];
int size,v[N][2],in[N],q[N],head,tail;
char s[N];
void init(){
	memset(t,0,sizeof t);
	memset(v,0,sizeof v);
	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[np].fa=t[q].fa=nq;
		for (;t[p].Next[c]==q;p=t[p].fa)
			t[p].Next[c]=nq;
	}
	return np;
}
void build(int x){
	scanf("%s",s+1);
	int n=strlen(s+1);
	for (int i=1,p=1;i<=n;i++)
		v[p=extend(p,s[i]-'a')][x]++;
}
int main(){
	init();
	build(0);
	build(1);
	memset(in,0,sizeof in);
	for (int i=2;i<=size;i++)
		in[t[i].fa]++;
	head=tail=0;
	for (int i=1;i<=size;i++)
		if (in[i]==0)
			q[++tail]=i;
	while (head<tail){
		int x=q[++head];
		for (int i=0;i<2;i++)
			v[t[x].fa][i]+=v[x][i];
		if ((--in[t[x].fa])==0)
			q[++tail]=t[x].fa;
	}
	LL ans=0;
	for (int i=2;i<=size;i++)
		ans+=1LL*v[i][0]*v[i][1]*(t[i].Max-t[t[i].fa].Max);
	printf("%lld",ans);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/zhouzhendong/p/BZOJ4566.html