BZOJ 2946 SA/SAM
思路:
1. 二分+后缀数组
2.SAM
//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=22222; int n,num,cntA ,cntB ,A ,B ,sa ,rk ,tsa ,ht ,rec ,vis[10]; char ch[5555],s ; void SA(){ for(int i=1;i<=n;i++)cntA[s[i]]++; for(int i=1;i<=256;i++)cntA[i]+=cntA[i-1]; for(int i=n;i;i--)sa[cntA[s[i]]--]=i; rk[sa[1]]=1; for(int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); for(int l=1;rk[sa ]<n;l<<=1){ memset(cntA,0,sizeof(cntA)); memset(cntB,0,sizeof(cntB)); for(int i=1;i<=n;i++) cntA[A[i]=rk[i]]++, cntB[B[i]=i+l<=n?rk[i+l]:0]++; for(int i=1;i<=n;i++)cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1]; for(int i=n;i;i--)tsa[cntB[B[i]]--]=i; for(int i=n;i;i--)sa[cntA[A[tsa[i]]]--]=tsa[i]; rk[sa[1]]=1; for(int i=2;i<=n;i++) rk[sa[i]]=rk[sa[i-1]]+(A[sa[i]]!=A[sa[i-1]]||B[sa[i]]!=B[sa[i-1]]); } for(int i=1,j=0;i<=n;i++){ j=j?j-1:0; while(s[i+j]==s[sa[rk[i]-1]+j])j++; ht[rk[i]]=j; } } bool check(int mid){ int cnt=0; for(int i=1;i<=n;i++){ if(ht[i]<mid)memset(vis,0,sizeof(vis)),cnt=0; else{ if(!vis[rec[sa[i]]])vis[rec[sa[i]]]=1,cnt++; if(!vis[rec[sa[i-1]]])vis[rec[sa[i-1]]]=1,cnt++; } if(cnt>=num)return 1; }return 0; } int main(){ scanf("%d",&num); for(int i=1;i<=num;i++){ scanf("%s",ch+1); int templen=strlen(ch+1); for(int j=1;j<=templen;j++)s[++n]=ch[j],rec =i; s[++n]=i; }SA(); int l=0,r=n,ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1; }printf("%d\n",ans); }
//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=4050; int n,m;char s ; struct SAM{ int ch [26],fa ,dis ,root,last,tot,ans ,v ,q ,maxx ; void init(){root=last=tot=1;} int newnode(int v){return dis[++tot]=v,tot;} void add(int x){ int p=last,np=newnode(dis[p]+1);last=np; for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np; if(!p)fa[np]=root; else{ int q=ch[p][x]; if(dis[q]==dis[p]+1)fa[np]=q; else{ int nq=newnode(dis[p]+1); memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q],fa[np]=fa[q]=nq; for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq; } } } void topsort(){ for(int i=1;i<=tot;i++)ans[i]=dis[i],v[dis[i]]++; for(int i=1;i<=tot;i++)v[i]+=v[i-1]; for(int i=tot;i;i--)q[v[dis[i]]--]=i; } void solve(){ memset(maxx,0,sizeof(maxx)); scanf("%s",s),n=strlen(s); int p=root,len=0; for(int i=0;i<n;i++){ int x=s[i]-'a'; if(ch[p][x])len++,p=ch[p][x]; else{ for(;p&&!ch[p][x];p=fa[p]); if(!p)p=root,len=0; else len=dis[p]+1,p=ch[p][x]; }maxx[p]=max(maxx[p],len); } for(int i=tot;i;i--){ int x=q[i]; ans[x]=min(ans[x],maxx[x]); if(maxx[x]&&fa[x])maxx[fa[x]]=max(maxx[fa[x]],dis[fa[x]]); } } }T; int main(){ T.init(); scanf("%d%s",&m,s),n=strlen(s); for(int i=0;i<n;i++)T.add(s[i]-'a'); T.topsort(); for(int i=1;i<m;i++)T.solve(); for(int i=1;i<=T.tot;i++)T.ans[1]=max(T.ans[1],T.ans[i]); printf("%d\n",T.ans[1]); }
- bzoj2946 [Poi2000]公共串(SA,SAM)
- bzoj4892 [Tjoi2017]dna(SAM/SA/二分答案+Hash)
- 【BZOJ 2946】 2946: [Poi2000]公共串 (SAM)
- [BZOJ4650][NOI2016]优秀的拆分(SAM构建SA)
- 【BZOJ2946】公共串 [SAM]
- [BZOJ2946][Poi2000]公共串解题报告|后缀自动机
- bzoj 2946: [Poi2000]公共串 后缀自动机
- bzoj 3676 [Apio2014]回文串(Manacher+SAM)
- bzoj4556 [Tjoi2016&Heoi2016]字符串(SA+二分答案+线段树)
- 【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)
- 【bzoj3926- [Zjoi2015]诸神眷顾的幻想乡】广义sam
- bzoj3998 [TJOI2015]弦论(SAM)
- [bzoj2946]公共串
- bzoj 3238 [Ahoi2013]差异(SAM解法)
- 【bzoj2946】[Poi2000]公共串 后缀自动机
- 【bzoj1528】[POI2005]sam-Toy Cars
- [BZOJ2946][POI2000]公共串(后缀自动机)
- 【BZOJ】【P3172】【Tjoi2013】【单词】【题解】【SAM】
- BZOJ2555【SAM】【LCT】
- [hdu4436 str2int]后缀自动机SAM(或后缀数组SA)