poj3415 Common Substrings(后缀数组,单调栈)

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≤ii+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) | kK, 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 ≤ Kmin{|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 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值