BZOJ2946: [Poi2000]公共串
2017-01-20 14:11
127 查看
传送门
总算是对SAM有个整体上的把握了。
关于SAM的性质有一句很经典的话:出现次数向父亲传递,接收串数从儿子获取。
可以说SAM很多经典题目就是这一句话的事。
求$N$个串的LCS,先用一个串建一个SAM。然后其串在SAM上跑,记录下在每个节点最长的$step$。对于一个串,跑完后在统计最小值到每个节点。
用基排按照每个点的$step$排序,然后倒序更新每个点即可。另外,在更新时,如果一个点是可以到达的,那么他的$pre$也一定能达到最长的长度。
因为$fa_{max}=now_{min}-1$。
总算是对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; }
相关文章推荐
- Bzoj2946 [Poi2000]公共串
- bzoj2946 [Poi2000]公共串(SAM)
- BZOJ2946 [Poi2000]公共串 【后缀自动机】
- BZOJ2946: [Poi2000]公共串
- bzoj2946 [Poi2000]公共串(SAM)
- bzoj2946: [Poi2000]公共串
- bzoj2946 [Poi2000]公共串 后缀自动机
- bzoj2946 [Poi2000]公共串(SA,SAM)
- 【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】
- BZOJ2946: [Poi2000]公共串
- 【BZOJ】【2946】【POI2000】公共串
- [BZOJ2946][Poi2000]公共串 && 后缀自动机
- 【BZOJ 2946】[Poi2000]公共串 后缀数组
- [BZOJ2946][Poi2000]公共串 后缀自动机
- bzoj 2946: [Poi2000]公共串 后缀自动机
- bzoj2946 [Poi2000]公共串(后缀数组 || 后缀自动机)
- 【bzoj2946】[Poi2000]公共串 后缀自动机
- 【BZOJ】2946: [Poi2000]公共串
- bzoj 2946: [Poi2000]公共串 后缀自动机
- [BZOJ2946][Poi2000]公共串(后缀自动机)