2019.02.22【HAOI2016】【BZOJ4566】【洛谷P3181】找相同字符(SAM)

BZOJ传送门

洛谷传送门


解析:

这种题显然就是建立一个SAM,拿另一个上去跑。

考虑跑到某一个点的贡献。显然就是 ∣ r i g h t ∣ ∗ ( l e n − m n [ s ] + 1 ) |right|*(len-mn[s]+1) right(lenmn[s]+1)

就是所有出现出现的次数*所有不同串长种类数。

显然这个是需要跳fail链统计的,我们维护一下每个位置被匹配的次数,最后从后向前统计一遍就行了


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

cs int N=200005; 
namespace SAM{
	int son[N<<1][26],fa[N<<1],len[N<<1],siz[N<<1],cnt[N<<1],f[N<<1];
	int last=1,now=1,l;
	
	inline void push_back(char c){
		c-='a';++l;
		int p=last,cur=++now;
		len[cur]=len[last]+1;siz[cur]=1;
		for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
		if(!p)fa[cur]=1;
		else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
		else {
			int clone=++now,q=son[p][c];
			memcpy(son[clone],son[q],sizeof son[q]);
			len[clone]=len[p]+1;
			fa[clone]=fa[q];
			fa[q]=fa[cur]=clone;
			for(;p&&son[p][c]==q;p=fa[p])son[p][c]=clone;
		}
		last=cur;
	}
	
	int a[N<<1],bin[N];
	inline void radix_sort(){
		for(int re i=1;i<=now;++i)++bin[len[i]];
		for(int re i=1;i<=l;++i)bin[i]+=bin[i-1];
		for(int re i=1;i<=now;++i)a[bin[len[i]]--]=i;
		for(int re i=now;i;--i)siz[fa[a[i]]]+=siz[a[i]];
	}
	
	ll ans;
	inline void calc(char *s,int l){
		int u=1,nowlen=0;
		for(int re i=0;i<l;++i){
			if(son[u][s[i]-'a']){u=son[u][s[i]-'a'];++nowlen;}
			else {
				while(u&&!son[u][s[i]-'a'])u=fa[u];
				if(!u)u=1,nowlen=0;
				else nowlen=len[u]+1,u=son[u][s[i]-'a'];
			}
			ans+=(ll)(nowlen-len[fa[u]])*siz[u];++cnt[u];
		}
		for(int re i=now;i>1;--i){
			int p=a[i];f[fa[p]]+=f[p]+cnt[p];
			ans+=(ll)f[p]*siz[p]*(len[p]-len[fa[p]]);
		}
		cout<<ans<<"\n";
	}
}

char s[N];int len;
signed main(){
	scanf("%s",s);len=strlen(s);
	for(int re i=0;i<len;++i)SAM::push_back(s[i]);
	SAM::radix_sort();
	scanf("%s",s);len=strlen(s);
	SAM::calc(s,len);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值