[SPOJ220]PHRASES - Relevant Phrases of Annihilation(后缀数组+二分)
来源:互联网 发布:淘宝照片拍摄方法 编辑:程序博客网 时间:2024/09/21 09:22
题目描述
传送门
题意:给定 n 个字符串,求在每个字符串中至少出现两次且不重叠的最长子串。
题解
先将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,再将后缀分组。判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并且在每个原来的字符串中,后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠)。
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define N 200005int T,t,n,m,la,Max,inf,ans;char a[N],s[N];int *x,*y,X[N],Y[N],c[N],sa[N],height[N],rank[N];int str[N],is_end[15],maxn[15],minn[15];void clear(){ t=n=m=la=Max=inf=ans=0; memset(a,0,sizeof(a));memset(s,0,sizeof(s)); memset(X,0,sizeof(X));memset(Y,0,sizeof(Y));memset(c,0,sizeof(c)); memset(sa,0,sizeof(sa));memset(height,0,sizeof(height));memset(rank,0,sizeof(rank)); memset(str,0,sizeof(str));memset(is_end,0,sizeof(is_end));memset(maxn,0,sizeof(maxn));memset(minn,0,sizeof(minn));}void build_sa(){ m=200; 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=0;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-1]+k<n?y[sa[i-1]+k]:-1)==(sa[i]+k<n?y[sa[i]+k]:-1))?p-1:p++; if (p>n) break; m=p; }}void build_height(){ for (int i=0;i<n;++i) rank[sa[i]]=i; int k=0;height[0]=0; for (int i=0;i<n;++i) { if (!rank[i]) continue; if (k) --k; int j=sa[rank[i]-1]; while (i+k<n&&j+k<n&&s[i+k]==s[j+k]) ++k; height[rank[i]]=k; }}bool check(int mid){ bool flag=false; int last=t-1; for (int i=t-1;i<=n;++i) { memset(maxn,-1,sizeof(maxn)); memset(minn,127,sizeof(minn));inf=minn[0]; if (height[i]<mid||i==n) { for (int j=last;j<i;++j) { maxn[str[sa[j]]]=max(maxn[str[sa[j]]],sa[j]); minn[str[sa[j]]]=min(minn[str[sa[j]]],sa[j]); } bool pd=true; for (int j=1;j<=t;++j) if (maxn[j]==-1||minn[j]==inf||maxn[j]-minn[j]<mid) { pd=false; break; } flag|=pd; last=i; } } return flag;}int find(){ int l=0,r=Max,mid,ans=0; while (l<=r) { mid=(l+r)>>1; if (check(mid)) ans=mid,l=mid+1; else r=mid-1; } return ans;}int main(){ scanf("%d\n",&T); while (T--) { clear(); scanf("%d\n",&t); for (int i=1;i<=t;++i) { gets(a);la=strlen(a); Max=max(Max,la); for (int j=0;j<la;++j) s[n++]=a[j],str[n-1]=i; if (i!=t) s[n++]='$',str[n-1]=i; is_end[i]=n-1; } is_end[t]=n; build_sa(); build_height(); for (int i=0;i<n;++i) height[i]=min(height[i],is_end[str[sa[i]]]-sa[i]); ans=find(); printf("%d\n",ans); }}
0 0
- [SPOJ220]PHRASES - Relevant Phrases of Annihilation(后缀数组+二分)
- SPOJ220:Relevant Phrases of Annihilation(后缀数组)
- SPOJ220---Relevant Phrases of Annihilation(后缀数组+二分,对后缀分组)
- SPOJ220---Relevant Phrases of Annihilation(后缀数组+二分,对后缀分组)
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分)
- Relevant Phrases of Annihilation spoj220
- spoj220 Relevant Phrases of Annihilation
- spoj 220 PHRASES - Relevant Phrases of Annihilation(后缀数组)
- SPOJ 220 PHRASES Relevant Phrases of Annihilation 后缀数组
- SPOJ 220 Relevant Phrases of Annihilation (后缀数组)
- Relevant Phrases of Annihilation SPOJ (后缀数组)
- 字符串练习题:SPOJ 220 Relevant Phrases of Annihilation(后缀数组加二分)
- SPOJ 220 . Relevant Phrases of Annihilation(后缀数组)
- 【后缀数组】【spoj 220】Relevant Phrases of Annihilation
- spoj 220 Relevant Phrases of Annihilation (后缀数组应用)
- SPOJ PHRASES Relevant Phrases of Annihilation
- SPOJ PHRASES Relevant Phrases of Annihilation
- Relevant Phrases of Annihilation SPOJ
- php 生成随机字符串
- EmBitz STM32 HAL 固件库之 GPIO
- 刚体Rigibody && 碰撞器Collider
- core data 介绍
- linux初学<习题六>显示文件类型!以及大小!
- [SPOJ220]PHRASES - Relevant Phrases of Annihilation(后缀数组+二分)
- CSDN博客的开通,写在2016的年末。
- python 判断网络连通
- [Leetcode] Search for a Range
- Django创建简易博客
- 用c++获取音频文件的信息 达到异步播放的效果(1)
- magical record 用法和介绍
- C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信
- ArrayList 和 LinkedList 和Vector使用上有什么区别?实现上有什么区别?