SPOJ 1811 LCS,SPOJ 1812 LCS2【SAM裸题,clj的ppt很清楚

8 篇文章 0 订阅
5 篇文章 0 订阅

反正clj的ppt都讲了

- LCS的话……因为只需要匹配一次,也就不需要更新pre的值了。

- 然而LCS2……因为有多个字符串要匹配,于是要把整个SAM上的rec都更新了,所以多了一步从后往前更新的

至于【rec[pre[k]]=dis[pre[k]]】……是因为……parent树的性质……max[pre[k]]=dis[pre[k]]<min[k],而既然k是可达的,说明pre上子串长度的任意取值都是可达的(原理就是对于某个状态i,i可以表示的串长度肯定比它在parent树上的父节点能表示的最大长度更大……l[i]>r[pre[i]])【woc好难解释啊QAQ,反正就是那个意思】



LCS ↓

#include<bits/stdc++.h>
#define MAXN 500057

//#define FLAZE_NAIVE

using namespace std;	char read_s[MAXN];

struct sam{
	int son[MAXN][26],pre[MAXN],dis[MAXN];
	int lst,cnt,lth;
	int p,q,np,nq;
	
	void insert(int x){
		dis[np=++cnt]=dis[p=lst]+1;
		lst=np;
		for(;p&&!son[p][x];p=pre[p])	son[p][x]=np;
		if(!p)	return pre[np]=1,void();
		q=son[p][x];
		if(dis[q]==dis[p]+1)	pre[np]=q;
		else{
			dis[nq=++cnt]=dis[p]+1;
			memcpy(son[nq],son[q],sizeof son[q]);
			pre[nq]=pre[q];
			pre[q]=pre[np]=nq;
			for(;p&&son[p][x]==q;p=pre[p])	son[p][x]=nq;
		}
	}
	
	void build(){
		cnt=lst=1;
		scanf("%s",read_s);
		lth=strlen(read_s);
		for(int i=0;i<lth;++i)	insert(read_s[i]-'a');
	}

#ifdef FLAZE_NAIVE	
	char tmp[MAXN];
	void dfs(int now,int stp){
		for(int i=0;i<26;++i)
			if(son[now][i]){
				tmp[stp]='a'+i;
				puts(tmp);
				dfs(son[now][i],stp+1);
			}
		tmp[stp]=' ';
	}
#endif

	int ans;
	void check(){
		ans=0;
		int now=1,tmp=0;
		scanf("%s",read_s);
		int str_len=strlen(read_s);
		for(int i=0;i<str_len;++i){
			int x=read_s[i]-'a';
			if(son[now][x])
				++tmp,now=son[now][x];
			else{
				for(;now&&!son[now][x];now=pre[now]);
				if(!now)
					now=1,tmp=0;
				else
					tmp=dis[now]+1,
					now=son[now][x];
			}
			ans=max(ans,tmp);
		}
	}

}SAM_s;

int main(){
	SAM_s.build();	
//	SAM_s.dfs(1,0);
	SAM_s.check();
	printf("%d",SAM_s.ans);
	return 0;
}

LCS2 ↓

#include<bits/stdc++.h>
#define MAXN 200057
#define INF 0x3f3f3f3f
//#define FLAZE_NAIVE
using namespace std;	char read_s[MAXN>>1];

struct t1{
	int son[MAXN][26],pre[MAXN],dis[MAXN];
	int cnt,lst;
	int lth;
	int p,np,q,nq;
	
	void insert(int x){
		dis[np=++cnt]=dis[p=lst]+1;
		lst=np;
		for(;p&&!son[p][x];p=pre[p])	son[p][x]=np;
		if(!p)	return 	pre[np]=1,void();
		q=son[p][x];
		if(dis[q]==dis[p]+1)	pre[np]=q;
		else{
			dis[nq=++cnt]=dis[p]+1;
			memcpy(son[nq],son[q],sizeof son[q] );
			pre[nq]=pre[q];
			pre[q]=pre[np]=nq;
			for(;p&&son[p][x]==q;p=pre[p])	son[p][x]=nq;
		}
	}	
	
	void build(){
		lst=cnt=1;
		scanf("%s",read_s);
		lth=strlen(read_s);
		for(int i=0;i<lth;++i)	insert(read_s[i]-'a');
	}
	
#ifdef FLAZE_NAIVE	
	char tmp[MAXN>>1];
	void dfs(int now,int stp){
		for(int i=0;i<26;++i)
			if(son[now][i]){
				tmp[stp]=97+i;
				puts(tmp);
				dfs(son[now][i],stp+1);
			}
		tmp[stp]=' ';
	}
#endif
	
	int s[MAXN],v[MAXN];
	void sort(){
		for(int i=1;i<=cnt;++i)	++v[dis[i]];
		for(int i=1;i<=lth;++i)	v[i]+=v[i-1];
		for(int i=1;i<=cnt;++i)	s[v[dis[i]]--]=i;
	} 
	
	int ans;
	int rec[MAXN];
	int pre_rec[MAXN];
	
	void check(){
		memset(rec,0,sizeof rec);
		int tmp=0,now=1;
		int l2=strlen(read_s);
		for(int i=0;i<l2;++i){
			int x=read_s[i]-'a';
			if(son[now][x])
				now=son[now][x],++tmp;
			else{
				for(;now&&!son[now][x];now=pre[now]);
				if(!now)
					now=1,tmp=0;
				else{
					tmp=dis[now]+1;
					now=son[now][x];
				}
			}
			rec[now]=max(rec[now],tmp);
		}
		for(int i=cnt;i;--i){
			int k=s[i];
			pre_rec[k]=min(pre_rec[k],rec[k]);
			if(rec[k]&&pre[k])	rec[pre[k]]=dis[pre[k]];
		}
	}
}SAM_s;


int main(){
	SAM_s.build();
//	SAM_s.dfs(1,0);	
	SAM_s.sort();
	memset(SAM_s.pre_rec,INF,sizeof SAM_s.pre_rec);
	while(~scanf("%s",read_s))	
		SAM_s.check();
	
	for(int i=1;i<=SAM_s.cnt;++i)	SAM_s.ans=max(SAM_s.ans,SAM_s.pre_rec[i]);
	printf("%d",SAM_s.ans);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值