• poj 3294 Life Forms【SA+二分】


    先加入未出现字符间隔把n个串连起来,注意如果串开的char这个间隔字符不能溢出,把这个接起来的串跑SA,二分答案k,判断的时候把连续一段he>=k的分成一组,然后看着一段是否包含了>n/2的串的后缀。
    统计是否出现这里可以用时间戳优化visit数组,就不用每次memset了
    输出答案的时候和二分判断一样,找到合法的子串就输出

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=200005;
    int m,n,wa[N],wb[N],wv[N],wsu[N],sa[N],rk[N],he[N],v[N],ti,de,bl[N];
    char s[N],t[N];
    bool cmp(int r[],int a,int b,int l)
    {
    	return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void saa(char r[],int n,int m)
    {
    	int *x=wa,*y=wb;
    	for(int i=0;i<=m;i++)
    		wsu[i]=0;
    	for(int i=1;i<=n;i++)
    		wsu[x[i]=r[i]]++;
    	for(int i=1;i<=m;i++)
    		wsu[i]+=wsu[i-1];
    	for(int i=n;i>=1;i--)
    		sa[wsu[x[i]]--]=i;
    	for(int j=1,p=1;j<n&&p<n;j<<=1,m=p)
    	{
    		p=0;
    		for(int i=n-j+1;i<=n;i++)
    			y[++p]=i;
    		for(int i=1;i<=n;i++)
    			if(sa[i]>j)
    				y[++p]=sa[i]-j;
    		for(int i=1;i<=n;i++)
    			wv[i]=x[y[i]];
    		for(int i=0;i<=m;i++)
    			wsu[i]=0;
    		for(int i=1;i<=n;i++)
    			wsu[wv[i]]++;
    		for(int i=1;i<=m;i++)
    			wsu[i]+=wsu[i-1];
    		for(int i=n;i>=1;i--)
    			sa[wsu[wv[i]]--]=y[i];
    		swap(x,y);
    		p=1;
    		x[sa[1]]=1;
    		for(int i=2;i<=n;i++)
    			x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p:++p;
    	}
    	for(int i=1;i<=n;i++)
    		rk[sa[i]]=i;
    	for(int i=1,j,k=0;i<=n;he[rk[i++]]=k)
    		for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
    }
    bool ok(int w)
    {
    	for(int i=2,la;i<=n;i=la+1)
    	{
    		la=i;
    		ti++;
    		int sm=0;
    		v[bl[sa[la-1]]]=ti,sm++;
    		while(he[la]>=w)
    		{
    			if(v[bl[sa[la]]]!=ti)
    				v[bl[sa[la]]]=ti,sm++;
    			la++;
    		}//cerr<<i<<" "<<la<<"   "<<sm<<endl;
    		if(sm>m/2)
    			return 1;
    	}
    	return 0;
    }
    int main()
    {
    	while(scanf("%d",&m)&&m)
    	{
    		n=0,de=26;
    		for(int j=1;j<=m;j++)
    		{
    			scanf("%s",t+1);
    			for(int i=1,len=strlen(t+1);i<=len;i++)
    				s[++n]=t[i]-'a',bl[n]=j;
    			s[++n]=++de,bl[n]=j;
    		}
    		saa(s,n,200);
    		int l=0,r=1000,ans=0;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(ok(mid))
    				l=mid+1,ans=mid;
    			else
    				r=mid-1;
    		}//cerr<<ans<<endl;
    		if(ans==0)
    		{
    			puts("?
    ");
    			continue;
    		}
    		for(int i=2,la;i<=n;i=la+1)
    		{
    			la=i;
    			ti++;
    			int sm=0;
    			v[bl[sa[la-1]]]=ti,sm++;
    			while(he[la]>=ans)
    			{
    				if(v[bl[sa[la]]]!=ti)
    					v[bl[sa[la]]]=ti,sm++;
    				la++;
    			}
    			if(sm>m/2)
    			{
    				for(int j=0;j<ans;j++)
    					if(s[sa[i]+j]<=26)
    						printf("%c",s[sa[i]+j]+'a');
    				puts("");
    			}
    		}
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    可以使用多少列创建索引?
    如何显示前 50 行?
    简单描述 MySQL 中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响-从读写两方面?
    实践中如何优化 MySQL ?
    列的字符串类型可以是什么?
    MySQL 里记录货币用什么字段类型好 ?
    什么是通用 SQL 函数?
    对于关系型数据库而言,索引是相当重要的概念?
    为表中得字段选择合适得数据类型?
    SQL 注入漏洞产生的原因?如何防止?
  • 原文地址:https://www.cnblogs.com/lokiii/p/9993620.html
Copyright © 2020-2023  润新知