【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; }
This passage is made by MashiroSky.