您的位置:首页 > 其它

BZOJ2946: [Poi2000]公共串

2017-01-20 14:11 127 查看
传送门

总算是对SAM有个整体上的把握了。

关于SAM的性质有一句很经典的话:出现次数向父亲传递,接收串数从儿子获取。

可以说SAM很多经典题目就是这一句话的事。

求$N$个串的LCS,先用一个串建一个SAM。然后其串在SAM上跑,记录下在每个节点最长的$step$。对于一个串,跑完后在统计最小值到每个节点。

用基排按照每个点的$step$排序,然后倒序更新每个点即可。另外,在更新时,如果一个点是可以到达的,那么他的$pre$也一定能达到最长的长度。

因为$fa_{max}=now_{min}-1$。

//POI2000
//by Cydiater
//2017.1.20
#include <iostream>
#include <queue>
#include <map>
#include <ctime>
#include <cstring>
#include <string>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <bitset>
#include <set>
#include <vector>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define FILE 		"pow"
const int MAXN=1e5+5;
const int oo=0x3f3f3f3f;
char s[MAXN];
int Max[MAXN],Min[MAXN];
int N,M,len,rnk[MAXN],cnt[MAXN],ans=0;
struct SAM{
int step[MAXN],son[MAXN][26],pre[MAXN],now,cnt;
SAM(){now=cnt=1;}
void Extend(int nxt){
int p=now,np=++cnt;now=np;
step[np]=step[p]+1;
for(;p&&!son[p][nxt];p=pre[p])son[p][nxt]=np;
if(!p)pre[np]=1;
else{
int q=son[p][nxt],nq;
if(step[q]==step[p]+1)pre[np]=q;
else{
step[(nq=++cnt)]=step[p]+1;
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
for(;son[p][nxt]==q;p=pre[p])son[p][nxt]=nq;
}
}
}
void Go(){
int Len=0,now=1;
up(i,1,len){
int nxt=s[i]-'a';
for(;!son[now][nxt]&&now;now=pre[now],Len=step[now]);
if(!now){now=1;Len=0;}
if(son[now][nxt]){
now=son[now][nxt];
cmax(Max[now],++Len);
}
}
}
}sam;
namespace solution{
void Prepare(){
cin>>N>>M;
scanf("%s",s+1);
len=strlen(s+1);
up(i,1,len)sam.Extend(s[i]-'a');
up(i,2,sam.cnt)cnt[sam.step[i]]++;
up(i,1,len)cnt[i]+=cnt[i-1];
up(i,2,sam.cnt)rnk[cnt[sam.step[i]]--]=i;
up(i,2,sam.cnt)Min[i]=sam.step[i];
}
void Solve(){
while(scanf("%s",s+1)!=EOF){
len=strlen(s+1);
sam.Go();
down(i,sam.cnt,1){
int node=rnk[i];
cmin(Min[node],Max[node]);
if(Max[node]&&sam.pre[node])
Max[sam.pre[node]]=sam.step[sam.pre[node]];
Max[node]=0;
}
}
up(i,1,sam.cnt)cmax(ans,Min[i]);
cout<<ans<<endl;
}
}
int main(){
//freopen("input.in","r",stdin);
//freopen(FILE".in","r",stdin);
//freopen(FILE".out","w",stdout);
using namespace solution;
Prepare();
Solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: