zoukankan      html  css  js  c++  java
  • POJ3294 Life Forms (后缀数组)

    POJ-3294 Life Forms (后缀数组)

    要按照字典序输出的话后缀自动机就比较麻烦了,所以没有

    把所有字符串接在一起,中间用不同的奇怪的字符隔开

    二分答案\(x\),将\(LCP\)数组分组使得每组中的\(LCP\ge x\),找一下是否一半的串都在这组中出现过了即可

    输出注意格式

    #include<cstdio> 
    #include<algorithm>
    #include<iostream>
    #include<cctype>
    #include<cstring>
    #include<cassert>
    using namespace std;
    
    #define reg register
    #define pb push_back
    typedef long long ll;
    typedef unsigned long long ull;
    #define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    char IO;
    int rd(){
    	int s=0;
    	int f=0;
    	while(!isdigit(IO=getchar())) f|=(IO=='-');
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    
    const int N=2e5+10,INF=1e9;
    
    int k,n,m;
    char str[N];
    int s[N],p[N];
    int cnt[N],tmp[N],rk[N<<1],sa[N],lcp[N],typ[N];
    
    void PreMake(){
    	memset(cnt,0,1300);
    	rep(i,1,n) cnt[s[i]]++;
    	rep(i,1,300) cnt[i]+=cnt[i-1];
    	rep(i,1,n) rk[i]=cnt[s[i]],sa[i]=i;
    	rep(i,n+1,n*2) rk[i]=0;
    	for(int k=1;k<=n;k<<=1) {
    		rep(i,0,n) cnt[i]=0;
    		rep(i,1,n) cnt[rk[i+k]]++;
    		rep(i,1,n) cnt[i]+=cnt[i-1];
    		drep(i,n,1) tmp[cnt[rk[i+k]]--]=i;
    		;
    		rep(i,0,n) cnt[i]=0;
    		rep(i,1,n) cnt[rk[i]]++;
    		rep(i,1,n) cnt[i]+=cnt[i-1];
    		drep(i,n,1) sa[cnt[rk[tmp[i]]]--]=tmp[i];
    		;
    		rep(i,1,n) tmp[sa[i]]=tmp[sa[i-1]]+(rk[sa[i]]!=rk[sa[i-1]]||rk[sa[i]+k]!=rk[sa[i-1]+k]);
    		rep(i,1,n) rk[i]=tmp[i];
    	}
        rep(i,1,n)lcp[i]=0;
    	int h=0;
    	rep(i,1,n) {
    		int j=sa[rk[i]-1];
    		if(h) h--;
    		while(i+h<=n && j+h<=n && s[i+h]==s[j+h]) h++;
    		lcp[rk[i]-1]=h;
    	}
    }
    
    int apr[N],apc;
    
    
    int Check(int lim) {
    	rep(i,1,m) apr[i]=0;apc=0;
    	rep(i,1,n) {
    		int j=i;
    		while(j<n && lcp[j]>=lim) j++;
    		rep(k,i,j) {
    			if(typ[sa[k]]) {
    				apc+=!apr[typ[sa[k]]];
    				apr[typ[sa[k]]]=1;
    			}
    		}
    		if(apc>m/2) return sa[i];
    		rep(k,i,j) apr[typ[sa[k]]]=0;
    		apc=0;
    		i=j;
    	}
    	return 0;
    }
    
    int fir=0;
    
    
    int main(){
    	while(~scanf("%d",&m) && m) {
    		p[1]=1;
    		rep(i,1,m) {
    			scanf("%s",str+1);
    			int len=strlen(str+1);
    			rep(j,1,len) s[p[i]+j-1]=str[j];
    			s[p[i]+len]=i+200;
    			p[i+1]=p[i]+len+1;
    		}
    		n=p[m+1]-1;
    		rep(i,1,n) typ[i]=0;
    		rep(i,1,m) rep(j,p[i],p[i+1]-2) typ[j]=i;
    		PreMake();
    		int l=1,r=n,res=-1;
    		while(l<=r) {
    			int mid=(l+r)>>1;
    			if(Check(mid)) l=mid+1,res=mid;
    			else r=mid-1;
    		}
    		if(fir) puts("");
    		else fir=1;
    		if(res==-1) { puts("?"); continue; }
    		rep(i,1,m) apr[i]=0;apc=0;
    		rep(i,1,n) {
    			int j=i;
    			while(j<n && lcp[j]>=res) j++;
    			rep(k,i,j) {
    				if(typ[sa[k]]) {
    					apc+=!apr[typ[sa[k]]];
    					apr[typ[sa[k]]]=1;
    				}
    			}
    			if(apc>m/2) {
    				rep(k,sa[i],sa[i]+res-1) putchar(s[k]);
    				puts("");
    			}
    			rep(k,i,j) apr[typ[sa[k]]]=0;
    			apc=0;
    			i=j;
    		}
    	}
    }
    
    
  • 相关阅读:
    学生党 应该去 研究研究 Socket(套接字) 实现原理
    收录一些 硬件 相关的 文章
    谈谈 软件 开源项目
    我决定 开启 一个 人工智能 机器学习 技术 的 普及项目 Let it Learn
    我邀请 民科吧 网友 和 三江老师 来 反相吧 辩论 调和级数
    共量子论 丢番图方程组 数值求解 最小分子解
    刚 看了一下 一元三次方程 的 解法
    研究发展 C 语言
    对 量子病态定理 提出的 代数方程 不成立 的 证明
    数学 改革
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12213662.html
Copyright © 2011-2022 走看看