BZOJ2946: [Poi2000]公共串
2018-03-08 20:11
393 查看
后缀数组 二分
题目传送门和HDU4080一个套路。
先把这几个串接起来,串和串之间用一个符号隔开。二分答案l,当连续一段h[i]的长度都≥l,且sa[i]分布在所有串中就满足。
代码:
#include<cstdio> #include<cstring> #include<algorithm> #define N 10010 using namespace std; int n,m,ti,sa ,rk ,rs ,t ,h ,L[6]; char s ,ch ; void RS(){ memset(rs,0,sizeof(rs)); for (int i=1;i<=n;i++) rs[rk[t[i]]]++; for (int i=1;i<=m;i++) rs[i]+=rs[i-1]; for (int i=n;i;i--) sa[rs[rk[t[i]]]--]=t[i]; } void SA(){ for (int i=1;i<=n;i++) rk[i]=s[i],t[i]=i; RS(); for (int j=1,p=0;j<=n;j<<=1,p=0){ for (int i=n-j+1;i<=n;i++) t[++p]=i; for (int i=1;i<=n;i++) if (sa[i]>j) t[++p]=sa[i]-j; RS(),memcpy(t,rk,sizeof(t)),p=rk[sa[1]]=1; for (int i=2;i<=n;i++) rk[sa[i]]=(t[sa[i]]==t[sa[i-1]]&&t[sa[i]+j]==t[sa[i-1]+j])?p:++p; if (p==n) break; m=p; } } void mkh(){ for (int i=1,k=0;i<=n;i++){ if (k) k--; while (s[i+k]==s[sa[rk[i]-1]+k]) k++; h[rk[i]]=k; } } bool pd(int l){ int sum=0; for (int i=1;i<=n;i++){ if (h[i]<l) sum=0; for (int j=1;j<=ti;j++) if (sa[i]<=L[j]){ sum|=1<<j-1; break; } if (sum==(1<<ti)-1) return true; } return false; } int main(){ scanf("%d",&ti); for (int i=1;i<=ti;i++){ scanf("%s",ch+1),L[i]=strlen(ch+1); for (int j=1;ch[j];j++) s[n+j]=ch[j]; n+=L[i],s[++n]='~',L[i]=n; } s[n--]=0,m=127,SA(),mkh(); int l=0,r=n,mid,ans=0; while (l<=r) if (pd(mid=l+r>>1)) ans=mid,l=mid+1; else r=mid-1; return printf("%d\n",ans),0; }
相关文章推荐
- bzoj2946 [Poi2000]公共串
- BZOJ2946: [Poi2000]公共串
- bzoj 2946: [Poi2000]公共串 后缀自动机
- 【bzoj2946】[Poi2000]公共串
- Bzoj2946:[POI2000] 最长公共子串
- Bzoj2946:[POI2000] 最长公共子串
- bzoj 2946: [Poi2000]公共串 (后缀自动机)
- 【BZOJ】2946: [Poi2000]公共串
- BZOJ 2946 [Poi2000]公共串 后缀自动机
- SPOJ LCS2 Longest Common Substring II + BZOJ 2946 [Poi2000]公共串
- 【二分答案】【哈希表】【字符串哈希】bzoj2946 [Poi2000]公共串
- bzoj 2946: [Poi2000]公共串
- [bzoj2946][后缀数组][Poi2000]公共串
- bzoj2946 [Poi2000]公共串(SA,SAM)
- BZOJ 2946: [Poi2000]公共串 后缀数组
- BZOJ 2946: [Poi2000]公共串( 后缀自动机 )
- [BZOJ2946][POI2000]公共串(后缀自动机)
- 【BZOJ2946】[Poi2000]公共串 后缀数组+二分
- BZOJ 2946 [Poi2000]公共串 ——后缀自动机
- BZOJ2946 [Poi2000]公共串 二分+hash