后缀自动机小练总结(Spoj1811&&Hdu4416&&CodeForces235C)

3 篇文章 0 订阅
3 篇文章 0 订阅

今天总体复习一下字符串……

后缀自动机是重点,以前就没学懂……

SPOJ1811LCS:

一个串建立自动机,另一个每个节点都在上面跑,记录当前可以匹配的长度更新ans即可

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3000000+10;
int ans=0; char s[maxn];
struct Suffix_Automation{
	int son[maxn][26],l[maxn],tmp;
	int last,tot,root,fa[maxn],lastp;
	void init(){
		tot=0; last=root=++tot; tmp=0; lastp=root;
	}
	void add(int w){
		int p=last,np=++tot; last=np; l[np]=l[p]+1;
		while (p&&!son[p][w]) son[p][w]=np,p=fa[p];
		if (!p){fa[np]=root;}
		else{
			int q=son[p][w];
			if (l[q]==l[p]+1) fa[np]=q;
			else{
				int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];
				for (int i=0;i<26;++i) son[nq][i]=son[q][i];
				fa[np]=fa[q]=nq;
				while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];
			}
		}
	}
	void solve_LCS(int w){
		if (son[lastp][w]) tmp++,ans=max(tmp,ans),lastp=son[lastp][w];
		else{
			while (lastp&&!son[lastp][w]) lastp=fa[lastp];
			if (!lastp) lastp=root,tmp=0;
			else tmp=l[lastp]+1,ans=max(ans,tmp),lastp=son[lastp][w];
		}
	}
}SAM;

int main(){
	SAM.init();
	scanf("%s",s+1); int n=strlen(s+1);
	for (int i=1;i<=n;++i)SAM.add(s[i]-'a');
	scanf("%s",s+1); n=strlen(s+1);
	for (int i=1;i<=n;++i)SAM.solve_LCS(s[i]-'a');
	printf("%d",ans);
}

Hdu4416

问A串中有多少个字串不是B的字串

做法基本同上一题,也是先建立一个自动机,另外一些在上面跑,在自动机上每个节点记录dep表示它可以与B中的串的最大匹配长度

然后一遍基数排序搞出一个具有拓扑性质的节点序列用儿子的dep更新fa的dep,那么l[x]-dep[x]即为当前节点的贡献

注意dep[x]==0时特判

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=220000;
int n; LL ans=0;
char s[maxn],t[maxn];

struct Suffix_Automation{
	int son[maxn][26],l[maxn];
	int last,root,tot,fa[maxn];
	int lastp,tmp; int dep[maxn];
	int c[maxn],rk[maxn];
	void init(){
		tot=0; last=root=++tot;
		memset(l,0,sizeof(l));
		memset(fa,0,sizeof(fa));
		memset(son,0,sizeof(son));
		memset(dep,0,sizeof(dep));
		memset(c,0,sizeof(c));
	}
	void add(int w){
		int p=last,np=++tot; last=np; l[np]=l[p]+1;
		while (p&&!son[p][w]) son[p][w]=np,p=fa[p];
		if (!p){fa[np]=root;}
		else{
			int q=son[p][w];
			if (l[q]==l[p]+1) fa[np]=q;
			else{
				int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];
				for (int i=0;i<26;++i) son[nq][i]=son[q][i];
				fa[np]=fa[q]=nq;
				while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];
			}
		}
	}
	void solvedep(int w){
		if (son[lastp][w]) lastp=son[lastp][w],tmp++,dep[lastp]=max(dep[lastp],tmp);
		else{
			while (lastp&&!son[lastp][w]) lastp=fa[lastp];
			if (!lastp) lastp=root,tmp=0;
			else tmp=l[lastp]+1,lastp=son[lastp][w],dep[lastp]=max(dep[lastp],tmp);
		}
	}
	void getans(int x){
		int mxl=0;
		for (int i=1;i<=tot;++i) c[l[i]]++,mxl=max(mxl,l[i]);
		for (int i=1;i<=mxl;++i) c[i]+=c[i-1];
		for (int i=1;i<=tot;++i) rk[c[l[i]]--]=i;
		for (int i=tot;i>=1;--i){
			int x=rk[i];
		    dep[fa[x]]=max(dep[fa[x]],dep[x]);
		    if (dep[x]&&dep[x]<l[x]) ans+=l[x]-dep[x];
		    else if (!dep[x]) ans+=l[x]-l[fa[x]];
		}
	}
}SAM;

void solve(int Case){
	scanf("%d",&n);
	SAM.init(); scanf("%s",s+1);
	int L=strlen(s+1); 
	for (int i=1;i<=L;++i) SAM.add(s[i]-'a');
	for (int i=1;i<=n;++i){
		scanf("%s",t+1); SAM.tmp=0; 
		int len=strlen(t+1); SAM.lastp=SAM.root; 
		for (int j=1;j<=len;++j) SAM.solvedep(t[j]-'a');
	}
	ans=0; SAM.getans(SAM.root);
	printf("Case %d: %lld\n",Case,ans);
}

int main(){
	int T; scanf("%d",&T);
	for (int i=1;i<=T;++i) solve(i);
}

Codeforces235C

给题解打个广告QAQ:题解

#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=2100000+10;
int n,lenS; LL ret;
vector<int>ans;
char s[maxn],t[maxn];
struct Suffix_Automation{
	int son[maxn][26],l[maxn],lastp;
	int tot,last,root,fa[maxn],tmp;
	int c[maxn],rk[maxn],num[maxn];
	bool flag[maxn];
	void init(){
		tot=0; last=root=++tot; 
		memset(flag,0,sizeof(flag));
	}
	void add(int w){
		int p=last,np=++tot; last=np; l[np]=l[p]+1; num[np]=1;
		while (p&&!son[p][w]) son[p][w]=np,p=fa[p];
		if (!p){fa[np]=root;}
		else{
			int q=son[p][w];
			if (l[q]==l[p]+1) fa[np]=q;
			else{
				int nq=++tot; l[nq]=l[p]+1; fa[nq]=fa[q];
				for (int i=0;i<26;++i) son[nq][i]=son[q][i];
				fa[np]=fa[q]=nq;
				while (p&&son[p][w]==q) son[p][w]=nq,p=fa[p];
			}
		}
	}
	void solvepre(int w){
		if (son[lastp][w]) lastp=son[lastp][w],tmp++;
		else{
			while (lastp&&!son[lastp][w]) lastp=fa[lastp];
			if (!lastp) lastp=root,tmp=0;
			else tmp=l[lastp]+1,lastp=son[lastp][w];
		}
		while (l[fa[lastp]]>=lenS){lastp=fa[lastp];tmp=l[lastp];}
		if (!flag[lastp]&&tmp>=lenS){ans.push_back(lastp);flag[lastp]=1;}
	}
	void getnum(){
		int mxl=0;
		for (int i=1;i<=tot;++i) c[l[i]]++,mxl=max(mxl,l[i]);
		for (int i=1;i<=mxl;++i) c[i]+=c[i-1];
		for (int i=tot;i;--i) rk[c[l[i]]--]=i;
		for (int i=tot;i;--i){
			int x=rk[i];
			num[fa[x]]+=num[x];
		}
	}
	void getans(){
		ret=0;
		for (int i=0;i<ans.size();++i){ret+=num[ans[i]];flag[ans[i]]=0;}
		ans.clear(); cout<<ret<<endl;
	}
}SAM;

int main(){
	SAM.init();
	scanf("%s",s+1); lenS=strlen(s+1);
	for (int i=1;i<=lenS;++i) SAM.add(s[i]-'a');
	SAM.getnum(); scanf("%d",&n);
	for (int i=1;i<=n;++i){
		scanf("%s",t+1); int len=strlen(t+1); lenS=len;
		for (int i=len+1;i<=len*2-1;++i) t[i]=t[i-len];
		len=len*2-1; SAM.lastp=SAM.root; SAM.tmp=0; 
		for (int j=1;j<=len;++j) SAM.solvepre(t[j]-'a');
		SAM.getans();
	}  
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值