【poj3294】 Life Forms

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

题意

  给定 n 个字符串,求出现在不小于 k 个字符串中的最长子串。

Solution

  后缀数组论文题。。

  将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,将后缀分成若干组,判断每组的后缀是否出现在不小于 k 个的原串中。这个做法的时间复杂度为 O(nlogn)。

  要求字典序从小到大排序的多组解,同样是利用rank进行排序即可。

细节

  strlen害死人→_→,好像默认的ACIll码只能到127。。

代码

// poj3294
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=200010;
int sa[maxn],rank[maxn],height[maxn],vis[200],belong[maxn],a[maxn],n,tot;
char s[maxn],ch[200];

namespace Suffix {
	int wa[maxn],wb[maxn],ww[maxn];
	bool cmp(int *r,int a,int b,int l) {
		return r[a]==r[b] && r[a+l]==r[b+l];
	}
	void da(char *r,int *sa,int n,int m) {
		int i,j,p,*x=wa,*y=wb;
		for (i=0;i<=m;i++) ww[i]=0;
		for (i=1;i<=n;i++) ww[x[i]=r[i]]++;
		for (i=1;i<=m;i++) ww[i]+=ww[i-1];
		for (i=n;i>=1;i--) sa[ww[x[i]]--]=i;
		for (p=0,j=1;p<n;j*=2,m=p) {
			for (p=0,i=n-j+1;i<=n;i++) y[++p]=i;
			for (i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
			for (i=0;i<=m;i++) ww[i]=0;
			for (i=1;i<=n;i++) ww[x[y[i]]]++;
			for (i=1;i<=m;i++) ww[i]+=ww[i-1];
			for (i=n;i>=1;i--) sa[ww[x[y[i]]]--]=y[i];
			for (swap(x,y),p=x[sa[1]]=1,i=2;i<=n;i++)
				x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p : ++p;
		}
	}
	void calheight(char *r,int *sa,int n) {
		for (int i=1;i<=n;i++) rank[sa[i]]=i;
		for (int k=0,i=1;i<=n;i++) {
			if (k) k--;
			int j=sa[rank[i]-1];
			while (s[i+k]==s[j+k]) k++;
			height[rank[i]]=k;
		}
	}
}
bool check(int len,int l,int p) {
	memset(vis,0,sizeof(vis));
	int flag=0,t=1,cnt=1;vis[belong[sa[1]]]=1;
	for (int i=2;i<=l;i++) {
		if (height[i]>=len) {
			if (vis[belong[sa[i]]]!=t) cnt++;
			vis[belong[sa[i]]]=t;
			flag|=(cnt>n/2);
			if (p && flag) return 1;
		}
		else {
			if (cnt>n/2) a[++tot]=sa[i-1];
			cnt=1;vis[belong[sa[i]]]=++t;
		}
	}
	flag|=(cnt>n/2);
	return flag;
}
bool cmp(int a,int b) {
	return rank[a]<rank[b];
}
int main() {
	int tmp;
	for (int i=1;i<'a';i++) ch[++tmp]=i;
	for (int i='z'+1;i<127;i++) ch[++tmp]=i;
	while (scanf("%d",&n)!=EOF && n) {
		int len=0;
		for (int i=1;i<=n;i++) {
			tmp=len;
			scanf("%s",s+len+1);
			len=strlen(s+1);
			for (int j=tmp+1;j<=len;j++) belong[j]=i;
			s[++len]=ch[i];
		}
		s[len]='\0';
		if (n==1) {printf("%s\n\n",s+1);continue;}
		Suffix::da(s,sa,len,200);
		Suffix::calheight(s,sa,len);
		int l=0,r=1000,ans=0;
		while (l<=r) {
			int mid=(l+r)>>1;tot=0;
			if (check(mid,len,1)) ans=mid,l=mid+1;
			else r=mid-1;
		}
		if (ans==0) {puts("?");puts("");continue;}
		tot=0;check(ans,len,0);
		sort(a+1,a+1+tot,cmp);
		for (int i=1;i<=tot;i++) {
			for (int j=1;j<=ans;j++) putchar(s[a[i]+j-1]);
			puts("");
		}
		puts("");
	}
    return 0;
}

 

posted @ 2017-01-13 11:26  MashiroSky  阅读(187)  评论(0编辑  收藏  举报