Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

雁过留声——后缀数组+扫描

Posted by fanhqme at 2010-01-10 16:26:30 on Problem 3415
这题的处理方法比较经典,
先把两个串拼接起来,之后利用后缀数组进行扫描。

这里要抓的精髓是:
1.如果有m个串和串x的最长公共前缀长度为n,那么
就产生m*(n-k+1)对匹配的串。
2.用一个栈(单调数组)维护已扫描的各个串和当前扫描的串的最长公共前缀长度。

需要注意的是:
1.拼接串的时候要加入分隔符。
2.只统计长度≥K的公共串

代码示例:
void DoubleAlgorithm(char *a,int n){
	int *tmp;
	SA=mem[3];Rank=mem[4];cnt=mem[0];tSA=mem[1];tRank=mem[2];
	for (int i=0;i<256;i++)cnt[i]=0;
	for (int i=0;i<n;i++)cnt[a[i]]++;
	for (int i=1;i<256;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)SA[--cnt[a[i]]]=i;
	Rank[SA[0]]=0;for (int i=1;i<n;i++)
		Rank[SA[i]]=Rank[SA[i-1]]+(a[SA[i]]!=a[SA[i-1]]);
	for (int l=1;l<n && Rank[SA[n-1]]!=n-1;l<<=1){
		for (int i=0;i<n;i++)cnt[Rank[SA[i]]]=i+1;
		for (int i=n-1;i>=0;i--)if (SA[i]>=l)
			tSA[--cnt[Rank[SA[i]-l]]]=SA[i]-l;
		for (int i=n-1;i>=0;i--)if (SA[i]+l>=n)
			tSA[--cnt[Rank[SA[i]]]]=SA[i];
		tRank[tSA[0]]=0;for (int i=1;i<n;i++)
			tRank[tSA[i]]=tRank[tSA[i-1]]+(
				Rank[tSA[i]]!=Rank[tSA[i-1]] ||
				Rank[tSA[i]+l]!=Rank[tSA[i-1]+l]);
		tmp=SA;SA=tSA;tSA=tmp;
		tmp=Rank;Rank=tRank;tRank=tmp;
	}
	int j;
	for (int i=0;i<n;i++){
		if (!Rank[i])Height[Rank[i]]=0;
		else{
			if (i && Height[Rank[i-1]]>1)j=Height[Rank[i-1]]-1;else j=0;
			for (;a[i+j]==a[SA[Rank[i]-1]+j];j++);
			Height[Rank[i]]=j;
		}
	}
}
int COUNT(int a){
	if (a<K)return 0;
	return a-K+1;
}

                scanf("%s",A);
		for (nA=0;A[nA];nA++);
		scanf("%s",A+nA+1);
		for (nB=0;A[nA+1+nB];nB++);
		N=nA+nB+1;
		A[nA]=1;A[N]=2;
		DoubleAlgorithm(A,N);
		ca=cnt;cb=tSA;
		ca[0]=cb[0]=0;
		for (int i=0;i<N;i++){
			ca[i+1]=(i?ca[i]:0);cb[i+1]=(i?cb[i]:0);
			if (SA[i]<nA)ca[i+1]++;
			else if (SA[i]>nA)cb[i+1]++;
		}
		ret=0;top=0;sa=sb=0;
		for (int i=0;i<N;i++){
			if (!i)continue;
			stA[top]=i-1;stB[top]=Height[i];top++;
			if (SA[i-1]<nA)sb+=COUNT(Height[i]);
			else if (SA[i-1]>nA)sa+=COUNT(Height[i]);
			while (top>1 && stB[top-2]>=stB[top-1]){
				if (stB[top-2]>stB[top-1]){
					sb-=(long long)(ca[stA[top-1]]-ca[stA[top-2]])*
						(long long)(COUNT(stB[top-2])-COUNT(stB[top-1]));
					sa-=(long long)(cb[stA[top-1]]-cb[stA[top-2]])*
						(long long)(COUNT(stB[top-2])-COUNT(stB[top-1]));
					stB[top-2]=stB[top-1];
				}
				top--;
			}
			if (SA[i]<nA)ret+=sa;
			else if (SA[i]>nA)ret+=sb;
		}
		printf("%I64d\n",ret);

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator