标签:
Common Substrings
Time Limit: 5000MS |
|
Memory Limit: 65536K |
Total Submissions: 8748 |
|
Accepted: 2899 |
Description
A substring of a string T is defined as:
T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|.
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):
S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}.
You are to give the value of |S| for specific A, B and K.
Input
The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.
1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.
Output
For each case, output an integer |S|.
Sample Input
2
aababaa
abaabaa
1
xx
xx
0
Sample Output
22
5
Source
POJ Monthly--2007.10.06, wintokk
【思路】
A与B长度至少为k的公共子串个数。
基本思想是将AB各个后缀的lcp-k+1的值求和。首先将两个字符串拼接起来中间用未出现的字符隔开,划分height数组,这首先保证了每一组中字符串之间的公共子串至少有k长度,组与组之间互不干扰。
问题变成了求一个组中一个A串与之前B串形成的LCP(lcp-k+1)和一个B串与之前A
串形成的LCP,问题是对称的,这里先解决第一个。用一个单调栈,栈中存放两个元素分别为height_top与cnt_top,分别表示到i为止的最小height和A串的数目。维护栈中元素的height从顶到底递减:每加入一个元素如果该元素比栈顶元素小则需要将tot中cnt_top个已经累计的height_top全部替换为当前元素的height(lcp是取区间最小值)。
时间复杂度为O(n)。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 400000 + 10; 9 10 int s[maxn]; 11 int sa[maxn],c[maxn],t[maxn],t2[maxn]; 12 13 void build_sa(int m,int n) { 14 int i,*x=t,*y=t2; 15 for(i=0;i<m;i++) c[i]=0; 16 for(i=0;i<n;i++) c[x[i]=s[i]]++; 17 for(i=1;i<m;i++) c[i]+=c[i-1]; 18 for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; 19 for(int k=1;k<=n;k<<=1) { 20 int p=0; 21 for(i=n-k;i<n;i++) y[p++]=i; 22 for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 23 for(i=0;i<m;i++) c[i]=0; 24 for(i=0;i<n;i++) c[x[y[i]]]++; 25 for(i=0;i<m;i++) c[i]+=c[i-1]; 26 for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; 27 swap(x,y); 28 p=1; x[sa[0]]=0; 29 for(i=1;i<n;i++) 30 x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 31 if(p>=n) break; 32 m=p; 33 } 34 } 35 int rank[maxn],height[maxn]; 36 void getHeight(int n) { 37 int i,j,k=0; 38 for(i=0;i<=n;i++) rank[sa[i]]=i; 39 for(i=0;i<n;i++) { 40 if(k) k--; 41 j=sa[rank[i]-1]; 42 while(s[j+k]==s[i+k]) k++; 43 height[rank[i]]=k; 44 } 45 } 46 47 int n,k; 48 char a[maxn],b[maxn]; 49 int sta[maxn][2]; 50 51 int main() { 52 while(scanf("%d",&k)==1 && k) { 53 scanf("%s%s",a,b); 54 int lena=strlen(a),lenb=strlen(b); 55 n=0; 56 for(int i=0;i<lena;i++) s[n++]=a[i]; 57 s[n++]=1; 58 for(int i=0;i<lenb;i++) s[n++]=b[i]; 59 s[n]=0; 60 61 build_sa(‘z‘+1,n+1); 62 getHeight(n); 63 64 int top=0; 65 LL ans=0,tot=0; 66 for(int i=1;i<=n;i++) { 67 if(height[i]<k) top=0,tot=0; 68 else { 69 int cnt=0; 70 if(sa[i-1]<lena) { 71 cnt++; tot+=height[i]-k+1; 72 } 73 while(top && height[i]<=sta[top-1][0]) { 74 top--; 75 tot+=(height[i]-sta[top][0])*sta[top][1]; 76 cnt+=sta[top][1]; 77 } 78 sta[top][0]=height[i],sta[top++][1]=cnt; 79 if(sa[i]>lena) ans+=tot; 80 } 81 } 82 top=tot=0; 83 for(int i=1;i<=n;i++) { 84 if(height[i]<k) top=0,tot=0; 85 else { 86 int cnt=0; 87 if(sa[i-1]>lena) { 88 cnt++; tot+=height[i]-k+1; 89 } 90 while(top && height[i]<=sta[top-1][0]) { 91 top--; 92 tot+=(height[i]-sta[top][0])*sta[top][1]; 93 cnt+=sta[top][1]; 94 } 95 sta[top][0]=height[i],sta[top++][1]=cnt; 96 if(sa[i]<lena) ans+=tot; 97 } 98 } 99 cout<<ans<<"\n"; 100 } 101 return 0; 102 }
poj3415 Common Substrings(后缀数组,单调栈)
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/5005079.html