[SPOJ220]PHRASES(后缀数组+二分)
2018-01-03 17:41
281 查看
题目:
我是超链接题意:
给定 n 个字符串,求在每个字符串中至少出现两次且不重叠的最长子串。题解:
1A和上道题基本一样啊,只不过不用倒过来了,二分,对于【至少出现两次】这个条件,我们以前也做过,在后缀分组内每组字符串给一个最大值最小值,差只要大于mid就好了
代码:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N=100005; int c ,X ,n,sa ,Y ,rak ,height ,len,m,fp,id ,s ,*x,*y; char st ;bool vis ; struct hh{int minn,maxx;}zu[20]; void build_sa() { m=300;x=X;y=Y; for (int i=0;i<m;i++) c[i]=0; for (int i=0;i<n;i++) c[x[i]=s[i]]++; for (int i=1;i<m;i++) c[i]+=c[i-1]; for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for (int k=1;k<=n;k<<=1) { int p=0; for (int i=n-k;i<n;i++) y[p++]=i; for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k; for (int i=0;i<m;i++) c[i]=0; for (int i=0;i<n;i++) c[x[y[i]]]++; for (int i=1;i<m;i++) c[i]+=c[i-1]; for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for (int i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&((sa[i]+k>=n?-1:y[sa[i]+k])==(sa[i-1]+k>=n?-1:y[sa[i-1]+k]))?p-1:p++; if (p>n) break; m=p; } } void build_lcp() { for (int i=0;i<n;i++) rak[sa[i]]=i; height[0]=0; int k=0; for (int i=0;i<n;i++) { if (rak[i]==0) continue; if (k) k--; int j=sa[rak[i]-1]; while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; height[rak[i]]=k; } } bool check(int mid) { int z; for (z=0;z<len;z++) zu[z].maxx=0,zu[z].minn=N; memset(vis,0,sizeof(vis)); for (int i=1;i<n;i++) if (height[i]>=mid) { vis[id[sa[i]]]=1; vis[id[sa[i-1]]]=1; zu[id[sa[i]]].maxx=max(zu[id[sa[i]]].maxx,sa[i]); zu[id[sa[i-1]]].maxx=max(zu[id[sa[i-1]]].maxx,sa[i-1]); zu[id[sa[i]]].minn=min(zu[id[sa[i]]].minn,sa[i]); zu[id[sa[i-1]]].minn=min(zu[id[sa[i-1]]].minn,sa[i-1]); } else { bool fff=1; for (z=0;z<len;z++) if (!vis[z] || zu[z].maxx-zu[z].minn<mid){fff=0;break;} if (fff) return 1; for (z=0;z<len;z++) zu[z].maxx=0,zu[z].minn=N; memset(vis,0,sizeof(vis)); } bool fff=1; for (z=0;z<len;z++) if (!vis[z] || zu[z].maxx-zu[z].minn<mid){fff=0;break;} if (fff) return 1; return 0; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&len); if (len==1) {scanf("%s",st);printf("%d\n",strlen(st));continue;} n=-1;fp=0; for (int i=0;i<len;i++) { scanf("%s",st); int ll=strlen(st); for (int j=0;j<ll;j++) s[++n]=st[j],id =i; s[++n]='#'+(fp++); } build_sa(); build_lcp(); int l=1,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); } }
相关文章推荐
- [SPOJ220]PHRASES - Relevant Phrases of Annihilation(后缀数组+二分)
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分)
- SPOJ220---Relevant Phrases of Annihilation(后缀数组+二分,对后缀分组)
- 字符串练习题:SPOJ 220 Relevant Phrases of Annihilation(后缀数组加二分)
- 【SPOJ220】Relevant Phrases of Annihilation(后缀数组,二分)
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
- SPOJ220---Relevant Phrases of Annihilation(后缀数组+二分,对后缀分组)
- SPOJ 220后缀数组:求每个字符串至少出现两次且不重叠的最长子串
- spoj220 每个字符串至少出现两次且不重叠的最长子串(后缀数组)
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
- spoj 220 Relevant Phrases of Annihilation (后缀数组 每个串中都至少出现两次的不重叠最长子串)
- SPOJ 220 后缀数组
- 【后缀数组】【spoj 220】Relevant Phrases of Annihilation
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
- 【后缀数组】SPOJ REPEATS
- poj1743(后缀数组+二分)
- 【SPOJ DISUBSTR】Distinct Substrings 后缀数组
- SPOJ DISUBSTR-----后缀数组求串的子串的个数
- SPOJ 705(后缀数组求单个子串的不重复子串个数)