poj3294 Life Forms(后缀数组+二分答案)

来源:互联网 发布:linux 发送post请求 编辑:程序博客网 时间:2024/05/28 23:10
求在≥k个串中出现过的最长子串.还是先都连起来,用特殊字符隔开,然后二分答案,按h分组,在一组内统计出现过的子串,满足条件就更新,注意可能有多个子串满足条件,按照顺序存下来就好了。大坑点见注释。(有人就拿char过了,很神。)
#include <cstdio>#include <cstring>#define N 102000int s[N];bool blank=0,vis[110];int belong[N],n,k,ans[N];int count[N],rank[N<<1],rank1[N],sa[N],tmp[N],h[N];inline int max(int x,int y){return x>y?x:y;}inline bool jud(int x){memset(vis,0,sizeof(vis));int num=0,cnt=0;for(int i=1;i<=n+1;++i){if(h[i]>=x){if(!vis[belong[sa[i]]]) vis[belong[sa[i]]]=1,cnt++;if(!vis[belong[sa[i-1]]]) vis[belong[sa[i-1]]]=1,cnt++;}else{if(cnt>k/2) ans[++num]=sa[i-1];cnt=0;memset(vis,0,sizeof(vis));}}if(num){ans[0]=num;return 1;} else return 0;}int main(){//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);while(1){n=0;int r=0;char str[1010]; scanf("%d",&k);if(!k) break;for(int i=1;i<=k;++i){//一定要转成int去做,char实在是伤不起啊。。//char 8字节,最高位符号位,所以当数值>127时就会变负的啊!//以后再也不要用char做了。。 scanf("%s",str+1);int len=strlen(str+1);r=max(r,len);for(int j=1;j<=len;++j) s[++n]=str[j]-'a'+1,belong[n]=i;s[++n]=100+i;belong[n]=i;}memset(count,0,sizeof(count));memset(rank,0,sizeof(rank));memset(h,0,sizeof(h));for(int i=1;i<=n;++i) count[s[i]]=1;for(int i=1;i<=200;++i) count[i]+=count[i-1];for(int i=n;i>=1;--i) rank[i]=count[s[i]];int kk=0;for(int p=1;kk!=n;p<<=1){memset(count,0,sizeof(count));for(int i=1;i<=n;++i) count[rank[i+p]]++;for(int i=1;i<=n;++i) count[i]+=count[i-1];for(int i=n;i>=1;--i) tmp[count[rank[i+p]]--]=i;memset(count,0,sizeof(count));for(int i=1;i<=n;++i) count[rank[tmp[i]]]++;for(int i=1;i<=n;++i) count[i]+=count[i-1];for(int i=n;i>=1;--i) sa[count[rank[tmp[i]]]--]=tmp[i];memcpy(rank1,rank,sizeof(rank1));rank[sa[1]]=kk=1;for(int i=2;i<=n;++i){if(rank1[sa[i]]!=rank1[sa[i-1]]||rank1[sa[i]+p]!=rank1[sa[i-1]+p]) ++kk;rank[sa[i]]=kk;}}kk=0;for(int i=1;i<=n;++i){if(rank[i]==1){h[1]=0;continue;}if(i==1||h[rank[i-1]]<=1) kk=0;if(kk) --kk;while(s[i+kk]==s[sa[rank[i]-1]+kk]) ++kk;h[rank[i]]=kk;}int l=1;while(l<=r){int mid=(l+r)>>1;if(jud(mid)) l=mid+1;else r=mid-1;}if(blank) puts("");else blank=1;if(l==1) puts("?");else for(int i=1;i<=ans[0];++i){for(int j=0;j<l-1;++j) putchar(s[ans[i]+j]+'a'-1);puts("");}}return 0;}


原创粉丝点击