| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
雁过留声——后缀数组+扫描这题的处理方法比较经典,
先把两个串拼接起来,之后利用后缀数组进行扫描。
这里要抓的精髓是:
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: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator