HDU 2328 Corporate Identity 后缀数组
2012-01-26 21:13
323 查看
求多个字符串的最长公共子串,若有多个输出字典序最小。
先复习一下,(i,j)表示排名i、j的串的最长公共前缀。(i,j) = min[(i,i+1),(i+1,i+2),......,(j-1,j)]。
两个字符串的最长公共前缀求法:
将两个字符串合起来,中间加个特殊符号,然后对整个字符串求后缀数组。
扫描height数组,如果排名i和i+1的串分别属于不同的原始串,则用height[i+1]更新结果。
那多个串的处理方法也类似:
把所有串合并起来,两两之间加特殊符号然后搞下后缀数组。
现在就是要找一个区间,要求每个原始字符串都至少要有一个子串在此区间内,那么这个区间内串的公共前缀必然是所有原始串的公共子串,于是就可以用这个区间内的最小height值更新结果。
这种区间如果有互相包含的话,外面那个肯定不用考虑,所以用se标记从左到右扫一遍就好,区间最小值用线段树求一下即可。
先复习一下,(i,j)表示排名i、j的串的最长公共前缀。(i,j) = min[(i,i+1),(i+1,i+2),......,(j-1,j)]。
两个字符串的最长公共前缀求法:
将两个字符串合起来,中间加个特殊符号,然后对整个字符串求后缀数组。
扫描height数组,如果排名i和i+1的串分别属于不同的原始串,则用height[i+1]更新结果。
那多个串的处理方法也类似:
把所有串合并起来,两两之间加特殊符号然后搞下后缀数组。
现在就是要找一个区间,要求每个原始字符串都至少要有一个子串在此区间内,那么这个区间内串的公共前缀必然是所有原始串的公共子串,于是就可以用这个区间内的最小height值更新结果。
这种区间如果有互相包含的话,外面那个肯定不用考虑,所以用se标记从左到右扫一遍就好,区间最小值用线段树求一下即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define SIZE 1000005 int N; char S[SIZE],S1[SIZE]; // SIZE > 256 int sa[SIZE], height[SIZE], rank[SIZE], tmp[SIZE], top[SIZE]; //rank[i] i是第几名 //sa[i] 第i名是什么 //height[i] 第i名和第i-1名的最长公共前缀长度 //名次:1~N 序号:0~N-1 struct Unit{ int v,id; bool friend operator<(Unit a,Unit b){ return a.v<b.v; } }; Unit sunit[SIZE]; void makesa(){ // O(SIZE * log SIZE) int i, j, n, len, na; n=N+1; S[n-1]=0; na = (n < 256 ? 256 : n); memset(top, 0, na * sizeof(int)); /*-------char------*/ for (i = 0; i < n ; i++) top[ rank[i] = S[i] & 0xff ]++; for (i = 1; i < na; i++) top[i] += top[i - 1]; for (i = 0; i < n ; i++) sa[ --top[ rank[i] ] ] = i; /*---------char----*/ /*-------int------- for(i=0;i<n;i++){ sunit[i].id=i; sunit[i].v=S[i]; } sort(sunit,sunit+n); int t=0; for(i=0;i<n;i++){ sa[i]=sunit[i].id; if(i&&sunit[i].v!=sunit[i-1].v){ t++;top[t+1]+=top[t]; } rank[sunit[i].id]=t;top[t+1]++; } for(t++;t<n;t++)top[t]=top[t-1]; //-----------------*/ for (len = 1; len < n; len <<= 1) { for (i = 0; i < n; i++) { j = sa[i] - len; if (j < 0) j += n; tmp[ top[ rank[j] ]++ ] = j; } sa[ tmp[ top[0] = 0 ] ] = j = 0; for (i = 1; i < n; i++) { if (rank[ tmp[i] ] != rank[ tmp[i-1] ] || rank[ tmp[i]+len ]!=rank[ tmp[i-1]+len ]) top[++j] = i; sa[ tmp[i] ] = j; } memcpy(rank, sa , n * sizeof(int)); memcpy(sa , tmp, n * sizeof(int)); if (j >= n - 1) break; } } void lcp(){ // O(4 * SIZE) int i, j, k,n=N+1; for (j = rank[height[i=k=0]=0]; i < n - 1; i++, k++) while (k >= 0 && S[i] != S[ sa[j-1] + k ]) height[j] = (k--), j = rank[ sa[j] + 1 ]; } int f_min(int x,int y){ return x<y?x:y; } int loc[1000000],num; void get_data(){ S[0]=0; char str[205]; int i,j=0; for(i=0;i<num;i++){ scanf("%s",str); if(!i){ strcat(S,str); for(;S[j];j++)loc[j]=i; }else{ strcat(S,"*"); loc[j++]=-1; strcat(S,str); for(;S[j];j++)loc[j]=i; } } N=j; makesa(); lcp(); } int mark[4000]; char best[10000],tbest[10000]; int len; struct Node{ int s,e,v; }; Node node[2100000]; int get_min(int loc,int s,int e){ if(node[loc].s==s&&node[loc].e==e)return node[loc].v; int mid=(node[loc].s+node[loc].e)>>1; if(e<=mid)return get_min(loc<<1,s,e); else if(s>mid)return get_min(loc<<1|1,s,e); else return f_min(get_min(loc<<1,s,mid),get_min(loc<<1|1,mid+1,e)); } void build_tree(int loc,int s,int e){ node[loc].s=s;node[loc].e=e; if(s==e){ node[loc].v=height[s]; return; } int mid=(s+e)>>1; build_tree(loc<<1,s,mid); build_tree(loc<<1|1,mid+1,e); node[loc].v=f_min(node[loc<<1].v,node[loc<<1|1].v); } // aca*ca*cac // 0123456789 void disp(){ int i; for(i=0;i<=N;i++)printf("%d ",sa[i]);printf("\n"); for(i=0;i<=N;i++)printf("%d ",loc[i]);printf("\n"); for(i=0;i<=N;i++)printf("%d ",rank[i]);printf("\n"); for(i=0;i<=N;i++)printf("%d ",height[i]);printf("\n"); } void run(){ if(num==1){ printf("%s\n",S); return; } build_tree(1,1,N); int s,e,cnt=0,tlen,i; // disp(); s=e=1; memset(mark,0,sizeof(mark)); best[0]=0;len=0; while(true){ while(e<=N&&cnt<num){ if(loc[sa[e]]!=-1&&!mark[loc[sa[e]]])cnt++; mark[loc[sa[e]]]++; e++; } if(cnt<num)break; while(true){ if(loc[sa[s]]==-1)s++; else if(mark[loc[sa[s]]]>1){ mark[loc[sa[s]]]--; s++; }else break; } // printf("%d %d s e ",s,e); tlen=get_min(1,s+1,e-1); // printf("%d\n",tlen); // for(i=sa[s];i<tlen;i++)if(S[i]=='*')break; // tlen=i; copy(S+sa[s],S+sa[s]+tlen,tbest); tbest[tlen]=0;//printf("%s * %s %d\n",tbest,best,strcmp(tbest,best)); if(tlen>len||tlen==len&&strcmp(tbest,best)<0){ len=tlen; strcpy(best,tbest); } mark[loc[sa[s]]]--;cnt--; s++; } if(!len)printf("IDENTITY LOST\n"); else printf("%s\n",best); } /* 4 asidugqw grweiudbq fwugcas wsfikuwgerf */ int main(){ while(scanf("%d",&num),num){ get_data(); run(); } return 0; }
相关文章推荐
- HDU 2328 Corporate Identity(后缀数组)
- HDU 2328 后缀数组
- hdu2328——Corporate Identity(后缀数组练习)
- hdu 2328 Corporate Identity (后缀数组应用)
- hdu 4691 Front compression(后缀数组)
- HDU 5769 (后缀数组)
- hdu 5030 Rabbit's String(后缀数组)
- HDU 2328 Corporate Identity(后缀数组-求多个串的最长共同子串)
- HDU 6194 string string string (2017沈阳网赛-后缀数组)
- HDU 5769 Substring (后缀数组)
- HDU 2328 Corporate Identity
- [后缀数组+枚举] hdu 3518 Boring counting
- HDU 5769 Substring(后缀数组)
- hdu 5442 长春区域赛网络赛 1006 Favorite Donut(后缀数组)
- HDU 4691(多校第九场1006) 后缀数组
- hdu 4691 lcp最长公共前缀 后缀数组经典模板
- hdu 4622(后缀自动机|后缀数组)
- hdu 2328 Corporate Identity (KMP)
- Poj 3080 Blue Jeans + Hdu 2328 Corporate Identity (后缀数组 字典序最小的最长公共子串)
- hdu 1403 Longest Common Substring (后缀数组模板)