zoukankan      html  css  js  c++  java
  • poj3294 Life Forms

    题目链接:http://poj.org/problem?id=3294

    题目大意:求出现在超过一半字符串中的最长子串


    解题思路:后缀数组+二分
    二分枚举最长子串的长度,根据height[]分组,验证是否存在 在一组中出现了超过一半次数的字符串。

    (这是height[]的应用之一,罗穗骞大大的论文里就有讲~)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 101000
    
    int sa[maxn],rk[maxn],Rsort[maxn];
    int h[maxn],y[maxn],wr[maxn],len;
    char s[maxn];int num[maxn];
    bool bo[110];int sk[maxn],as[maxn];
    int mymax(int x,int y){return (x>y)?x:y;}
    bool cmp(int x,int y,int k){return (wr[x]==wr[y])&&(wr[x+k]==wr[y+k]);}
    void get_h()
    {	
    	int i,k=0;
    	for (i=1;i<=len;i++)
    	{
    		int j=sa[rk[i]-1];
    		if (k>0) k--;
    		while (s[i+k]==s[j+k]) k++;
    		h[rk[i]]=k;
    	}
    }
    void get_sa()
    {
    	int i,k,ln,p,m=127;
    	for (i=1;i<=len;i++) rk[i]=s[i];
    	for (i=0;i<=m;i++) Rsort[i]=0;
    	for (i=1;i<=len;i++) Rsort[rk[i]]++;
    	for (i=1;i<=m;i++) Rsort[i]+=Rsort[i-1];
    	for (i=len;i>=1;i--) sa[Rsort[rk[i]]--]=i;
    	p=0;ln=1;
    	while (p<len)
    	{
    		for (k=0,i=len-ln+1;i<=len;i++) y[++k]=i;
    		for (i=1;i<=len;i++) if (sa[i]-ln>0) y[++k]=sa[i]-ln;
    		for (i=1;i<=len;i++) wr[i]=rk[y[i]];
    		for (i=0;i<=m;i++) Rsort[i]=0;
    		for (i=1;i<=len;i++) Rsort[wr[i]]++;
    		for (i=1;i<=m;i++) Rsort[i]+=Rsort[i-1];
    		for (i=len;i>=1;i--) sa[Rsort[wr[i]]--]=y[i];
    		memcpy(wr,rk,sizeof(wr));
    		p=1;rk[sa[1]]=1;
    		for (i=2;i<=len;i++)
    		{
    			if (!cmp(sa[i],sa[i-1],ln)) p++;
    			rk[sa[i]]=p;
    		}m=p;ln*=2;
    	}s[0]=sa[0]=0;
    }
    
    int main()
    {
    	//freopen("a.in","r",stdin);
    	//freopen("a.out","w",stdout);
    	int n,mxl,i,j,l,L,R,mid,ll;
    	int ans,id,w;char ss[1100];
    	bool tk=0;
    	while (1)
    	{
    		scanf("%d
    ",&n);
    		if (tk && n!=0) printf("
    ");
    		if (n==0) break;tk=1;
    		len=0;mxl=ll=0;ans=-1;
    		memset(s,'',sizeof(s));
    		for (i=1;i<=n;i++)
    		{
    			scanf("%s",ss+1);
    			l=strlen(ss+1);
    			mxl=mymax(mxl,l);
    			for (j=1;j<=l;j++) 
    			{
    				s[++len]=ss[j];
    				num[len]=i;//num[i]存的是s[i]属于哪一个串
    			}if (i!=n) s[++len]=i;
    		}
    		if (n==1) {printf("%s
    
    ",ss+1);continue;}
    		get_sa();get_h();
    		L=1;R=mxl;w=-1;
    		memset(bo,false,sizeof(bo));
    		while (L<=R)//二分
    		{
    			bool bk=0;mid=(L+R)>>1;
    			int sum=0;id=0;
    			for (i=1;i<=len;i++)
    			{
    				if (!bo[num[sa[i]]])
    				{
    					bo[num[sa[i]]]=1;
    					sum++;//统计出现了几个不同串的
    				}
    				if (h[i+1]<mid)
    				{
    					if (sum*2>n) {bk=1;sk[++id]=w;}//记录
    					memset(bo,0,sizeof(bo));sum=0;w=sa[i+1];
    				}
    			}
    			if (!bk) R=mid-1;
    			else
    			{
    				L=mid+1;ans=mid;ll=id;
    				memcpy(as,sk,sizeof(sk));
    			}
    		}
    		if (ans==-1) printf("?
    ");
    		else {
    			for (i=1;i<=ll;i++)
    			{
    				for (j=as[i];j<as[i]+ans;j++)
    				printf("%c",s[j]);
    				printf("
    ");
    			}
    		}
    	}
    	return 0;
    }


  • 相关阅读:
    BZOJ 1040 (ZJOI 2008) 骑士
    BZOJ 1037 (ZJOI 2008) 生日聚会
    ZJOI 2006 物流运输 bzoj1003
    ZJOI 2006 物流运输 bzoj1003
    NOI2001 炮兵阵地 洛谷2704
    NOI2001 炮兵阵地 洛谷2704
    JLOI 2013 卡牌游戏 bzoj3191
    JLOI 2013 卡牌游戏 bzoj3191
    Noip 2012 day2t1 同余方程
    bzoj 1191 [HNOI2006]超级英雄Hero——二分图匹配
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527885.html
Copyright © 2011-2022 走看看