HDU 2328 Corporate Identity 后缀数组

求多个字符串的最长公共子串,若有多个输出字典序最小。


先复习一下,(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
#include
#include
#include
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= 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>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&&cnt1){
				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];ilen||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;
}



你可能感兴趣的:(解题报告)