字符串(后缀数组):POJ 3415 Common Substrings

Common Substrings
 

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
  这道题呃,有些考验程序实践能力。
  题意:对于给定的两个字符串和一个整数K,求两个字符串长度大于等于K的公共子串数目。
  将两个字符串接起来,中间用一个特殊字符隔开,枚举Lcp,暴力枚举是O(n³)的,死活都不可能过。
  这是我们想:能否使用以前枚举的信息?所以正解就出来了:单调栈优化!
  具体咋打就看代码吧~~~


  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 using namespace std;
  5 const int maxn=400010;
  6 char S[maxn];
  7 int sa[maxn],r[maxn],rank[maxn],lcp[maxn];
  8 int Wv[maxn],Ws[maxn],Wa[maxn],Wb[maxn],len;
  9 
 10 bool cmp(int *p,int a,int b,int l){
 11     return p[a]==p[b]&&p[a+l]==p[b+l];
 12 }
 13 
 14 void DA(int n,int m){
 15     int i,j,p,*x=Wa,*y=Wb,*t;
 16     for(i=0;i<m;i++)Ws[i]=0;
 17     for(i=0;i<n;i++)++Ws[x[i]=r[i]];
 18     for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
 19     for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;
 20     
 21     for(j=1,p=1;p<n;m=p,j<<=1){
 22         for(p=0,i=n-j;i<n;i++)y[p++]=i;
 23         for(i=0;i<n;i++)
 24             if(sa[i]>=j)
 25                 y[p++]=sa[i]-j;
 26         
 27         for(i=0;i<m;i++)Ws[i]=0;
 28         for(i=0;i<n;i++)++Ws[Wv[i]=x[y[i]]];
 29         for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
 30         for(i=n-1;i>=0;i--)
 31             sa[--Ws[Wv[i]]]=y[i];
 32         
 33         for(t=x,x=y,y=t,i=1,p=1,x[sa[0]]=0;i<n;i++)
 34             x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
 35     }
 36 }
 37 
 38 void Lcp(int n){
 39     int i,j,k=0;
 40     for(i=1;i<=n;i++)rank[sa[i]]=i;
 41     for(i=0;i<n;lcp[rank[i++]]=k)
 42         for(k?--k:k,j=sa[rank[i]-1];r[i+k]==r[j+k];++k);
 43 }
 44 
 45 int s[maxn][2];
 46 
 47 int main(){
 48     int n,k;
 49     while(~scanf("%d",&k)&&k){
 50         scanf("%s",S);
 51         n=strlen(S);S[n]='%';
 52         scanf("%s",S+n+1);
 53         len=strlen(S);
 54         for(int i=0;i<len;i++)
 55             r[i]=S[i];
 56         r[len]=0;
 57         DA(len+1,128);
 58         Lcp(len);
 59         
 60         int cnt=0;
 61         long long ans=0,sum=0;
 62         for(int i=1;i<=len;i++){
 63             if(lcp[i]<k){
 64                 sum=0;cnt=0;
 65                 continue;
 66             }
 67             int tot=0;
 68             if(sa[i-1]>n){
 69                 sum+=lcp[i]-k+1;
 70                 tot++;
 71             }
 72             while(cnt&&s[cnt][0]>=lcp[i]){
 73                 tot+=s[cnt][1];
 74                 sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]);
 75                 cnt--;
 76             }
 77             s[++cnt][0]=lcp[i];
 78             s[cnt][1]=tot;    
 79             if(sa[i]<n)ans+=sum;
 80         }
 81         cnt=0;sum=0;
 82         for(int i=1;i<=len;i++){
 83             if(lcp[i]<k){
 84                 sum=0;cnt=0;
 85                 continue;
 86             }
 87             int tot=0;
 88             if(sa[i-1]<n){
 89                 sum+=lcp[i]-k+1;
 90                 tot++;
 91             }
 92             while(cnt&&s[cnt][0]>=lcp[i]){
 93                 tot+=s[cnt][1];
 94                 sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]);
 95                 cnt--;
 96             }
 97             s[++cnt][0]=lcp[i];
 98             s[cnt][1]=tot;    
 99             if(sa[i]>n)ans+=sum;
100         }        
101         printf("%lld\n",ans);
102     }
103     return 0;
104 }

 


posted @ 2016-03-18 22:32  TenderRun  阅读(333)  评论(0编辑  收藏  举报