洛谷3181 BZOJ4566 HAOI2016 找相同字符 SAM

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/84783458

题目链接

题意:
给你两个字符串,求这两个字符串有多少对相同的子串,本质相同但位置不同算不同。串长<=2e5

题解:
我们考虑像以往一样对于第一个串建SAM,让第二个串在SAM上跑并统计答案,结果我们发现这样并不能做。。。

于是这个题的做法是把两个串建成一个SAM,中间用一个特殊字符隔开。两个串建成一个SAM之后,我们发现可以对SAM形成的DAG拓扑排序,然后从拓扑序大的往拓扑序小的更新答案,实质上应该是parent树上儿子更新父亲,两种写法应该是等价的。更新的是一个点在第一个串和第二个串分别的right集合大小,写法可以看看代码。因为parent树上的子节点表示的字符串都包含了父节点表示的字符串,子节点的right中的每一个元素也都包含了父节点表示的字符串,而在 l e n [ f a [ x ] ] len[fa[x]] l e n [ x ] len[x] 之间的所有字符串都不会在parent树上更接近根的地方再出现,所以就一起在这里统计答案。所以在一个点那里对答案的贡献就是 ( l e n [ x ] l e n [ f a [ x ] ] ) c n t 1 [ x ] c n t 2 [ x ] (len[x]-len[fa[x]])*cnt1[x]*cnt2[x] 。答案要开long long。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,nn,qwq,fa[1600010],ch[1600010][26],len[1600010],rt=1,lst=1,cnt=1;
int sz[1600010],a[1600010],rk[1600010],cnt1[1600010],cnt2[1600010];
char s[500010],s1[200010];
long long ans;
inline void insert(int x)
{
	int cur=++cnt,pre=lst;
	lst=cur;
	len[cur]=len[pre]+1;
	for(;pre&&!ch[pre][x];pre=fa[pre])
	ch[pre][x]=cur;
	if(!pre)
	fa[cur]=rt;
	else
	{
		int ji=ch[pre][x];
		if(len[ji]==len[pre]+1)
		fa[cur]=ji;
		else
		{
			int gg=++cnt;
			memcpy(ch[gg],ch[ji],sizeof(ch[ji]));
			len[gg]=len[pre]+1;
			fa[gg]=fa[ji];
			fa[ji]=fa[cur]=gg;
			for(;pre&&ch[pre][x]==ji;pre=fa[pre])
			ch[pre][x]=gg;
		}
	}
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	qwq=n;
	scanf("%s",s1+1);
	nn=strlen(s1+1);
	s[++n]='#';
	for(int i=1;i<=nn;++i)
	s[++n]=s1[i];
	for(int i=1;i<=n;++i)
	insert(s[i]-'a');
	for(int i=1;i<=cnt;++i)
	a[len[i]]++;
	for(int i=1;i<=n;++i)
	a[i]+=a[i-1];
	for(int i=cnt;i>=1;--i)
	rk[a[len[i]]--]=i;
	int ji=rt;
	for(int i=1;i<=n;++i)
	{
		int x=s[i]-'a';
		ji=ch[ji][x];
		if(len[ji]<=qwq+1)
		++cnt1[ji];
		else
		++cnt2[ji];
	}
	for(int i=cnt;i>=1;--i)
	{
		cnt1[fa[rk[i]]]+=cnt1[rk[i]];
		cnt2[fa[rk[i]]]+=cnt2[rk[i]];
	}
	for(int i=1;i<=cnt;++i)
	ans+=1ll*cnt1[i]*cnt2[i]*(len[i]-len[fa[i]]);		
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/84783458
今日推荐