hdu 2328 Corporate Identity
http://acm.hdu.edu.cn/showproblem.php?pid=2328
题意:求多个字符串的最长公共子串,若有多个输出字典序最小。
思路:先进行后缀数组操作。然后二分子串长度,根据height和sa数组的值,判断当前长度是否合适。
当然,这里面还有hash映射的。

#include<stdio.h> #include<string.h> #include<stdlib.h> const int maxn = 910000; int wn[maxn],wa[maxn],wb[maxn],wv[maxn],as[maxn],sa[maxn],rank[maxn],height[maxn]; int sta[maxn],hash[5000],bs[maxn],n,ansx; char r[maxn],ans[1000]; int Max(int x,int y){return x>y?x:y;} int Min(int x,int y){return x>y?y:x;} int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i = 0; i < m; ++ i) wn[i] = 0; for(i = 0; i < n; ++ i) wn[x[i]=r[i]]++; for(i = 1; i < m; ++ i) wn[i] += wn[i-1]; for(i = n - 1; i >= 0; --i) sa[--wn[x[i]]] = i; for(p = 1,j = 1; p < n; j *= 2,m = p) { for(p = 0,i = n-j; i < n; ++ i) y[p++] =i; for(i = 0; i < n; ++ i) if(sa[i]>=j) y[p++] = sa[i] - j; for(i = 0; i < m; ++ i) wn[i] = 0; for(i = 0; i < n; ++ i) wn[wv[i]=x[y[i]]]++; for(i = 1; i < m; ++ i) wn[i] += wn[i-1]; for(i = n - 1; i >= 0; --i) sa[--wn[wv[i]]] = y[i]; for(t = x,x = y,y = t,x[sa[0]] = 0,p=1,i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(int *r,int *sa,int n) { int i,j,k = 0; for(i = 1; i <= n; ++ i){ rank[sa[i]] = i; height[i] = 0;} for(i = 0; i < n; height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k];++k); } bool check(int x,int L) { int i,j=0,k = 0; memset(hash,-1,sizeof(hash)); hash[0] = 0;--L; for(i = 1; i < L; ++ i) { if(height[i]>=x){ if(!j){ k+= hash[bs[sa[i-1]]]; hash[bs[sa[i-1]]] = 0; j = 1; } k += hash[bs[sa[i]]]; hash[bs[sa[i]]] = 0; }else{ k *= -1; if(k>=n){ if(x>ansx){ for(j = 0; j < x; ++ j) ans[j] = r[sa[i-1]+j]; ans[j] = 0; ansx = x; } return 1; } k = 0; memset(hash,-1,sizeof(hash)); hash[0] = 0; j = 0; } }return 0; } int main() { int i,j,k,m,cnt,L,t,mixn; char str[1000]; while(scanf("%d",&n)!=EOF&&n) { k = 199; L = 0; mixn = 200; for(j = 0; j < n; ++ j) { sta[j] = L; scanf("%s",str); strcpy(r+L,str); for(i = 0; str[i]; ++ i) as[L++] = static_cast<int>(str[i]); if(i<mixn)mixn = i; r[L] = '#'; as[L++] = ++k; } sta[j] = L; r[L-1] = 0; as[L-1] = 0; da(as,sa,L,k); calheight(as,sa,L-1); for(i=j=0; i < L; ++ i) if(i<sta[j]) bs[i] = j; else bs[i] = ++j; for(i = 1; i <= n; ++ i) bs[sta[i]-1] = 0; int low = 0,high = mixn+1,mid; ansx = 0; while(low<high-1) { mid = (low + high)>>1; if(check(mid,L))low = mid; else high = mid; } if(ansx) puts(ans); else puts("IDENTITY LOST"); }return 0; }