poj 3415 後綴數組 兩個字符串中長度不小於 k 的公共子串的個數

Common Substrings
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 11469   Accepted: 3796

Descriptionios

A substring of a string T is defined as:數組

 

T( ik)= TiTi +1... Ti+k -1, 1≤ ii+k-1≤| T|.

 

Given two strings AB and one integer K, we define S, a set of triples (ijk):spa

 

S = {( ijk) |  kKA( ik)= B( jk)}.

 

You are to give the value of |S| for specific AB and K.code

Inputblog

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.ip

1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.ci

 

Output字符串

For each case, output an integer |S|.get

Sample Inputinput

2
aababaa
abaabaa
1
xx
xx
0

Sample Output

22
5

Source

題意:
給定兩個字符串 A 和 B,求長度不小於 k 的公共子串的個數(能夠相同)
代碼:
//論文題,按照規矩先把兩個串連起來求出heigh數組,heigh數組分組(大於等於k的一組),而後每遇到一個B串就讓他和前面的A串求
//lcp,貢獻就是lcp-k+1,而後反過來再求一次每一個A和前面的B的,但這是n^2的。咱們考慮求某個B與前面的A的lcp時是求這一段中的最小
//的heigh值,這樣咱們能夠用一個遞增的棧來存儲heigh數組把貢獻疊加起來,要入棧的元素小於棧頂時對後面的B的貢獻值會減少,而且
//還要保存由於他的入棧而出棧了多少大於等於他的元素以備後面的操做(減少貢獻值),每遇到B就更新答案。
//這題仍是很難的
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN=300000;
int sa[MAXN+9],he[MAXN+9],ra[MAXN+9],xx[MAXN+9],yy[MAXN+9],buc[MAXN+9],q[MAXN+9][2];
char s[MAXN+9];
int len,m;
void get_suf()
{
    int *x=xx,*y=yy;
    for(int i=0;i<m;i++) buc[i]=0;
    for(int i=0;i<len;i++) buc[x[i]=s[i]]++;
    for(int i=1;i<m;i++) buc[i]+=buc[i-1];
    for(int i=len-1;i>=0;i--) sa[--buc[x[i]]]=i;
    for(int k=1;k<=len;k<<=1){
        int p=0;
        for(int i=len-1;i>=len-k;i--) y[p++]=i;
        for(int i=0;i<len;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(int i=0;i<m;i++) buc[i]=0;
        for(int i=0;i<len;i++) buc[x[y[i]]]++;
        for(int i=1;i<m;i++) buc[i]+=buc[i-1];
        for(int i=len-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(int i=1;i<len;i++){
            if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])
                x[sa[i]]=p-1;
            else x[sa[i]]=p++;
        }
        if(p>=len) break;
        m=p;
    }
    for(int i=0;i<len;i++) ra[sa[i]]=i;
    int k=0;
    for(int i=0;i<len;i++){
        if(ra[i]==0) { he[0]=0; continue; }
        if(k) k--;
        int j=sa[ra[i]-1];
        while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++;
        he[ra[i]]=k;
    }
}
ll solve(int len1,int k)
{
    ll ans=0,cnt=0,sum=0,top=0;
    for(int i=1;i<len;i++){
        if(he[i]<k) { top=sum=0;continue; }
        cnt=0;
        if(sa[i-1]<len1) { cnt++;sum+=he[i]-k+1; }
        while(top&&he[i]<=q[top][1]){
            sum-=q[top][0]*(q[top][1]-he[i]);
            cnt+=q[top--][0];
        }
        q[++top][0]=cnt;
        q[top][1]=he[i];
        if(sa[i]>len1) ans+=sum;
    }
    sum=0;top=0;
    for(int i=1;i<len;i++){
        if(he[i]<k) { top=sum=0;continue; }
        cnt=0;
        if(sa[i-1]>len1) { cnt++;sum+=he[i]-k+1; }
        while(top&&he[i]<=q[top][1]){
            sum-=q[top][0]*(q[top][1]-he[i]);
            cnt+=q[top--][0];
        }
        q[++top][0]=cnt;
        q[top][1]=he[i];
        if(sa[i]<len1) ans+=sum;
    }
    return ans;
}
int main()
{
    int k;
    while(scanf("%d",&k)&&k){
        scanf("%s",s);
        int len1=strlen(s);
        s[len1]='#';
        scanf("%s",s+len1+1);
        len=strlen(s);
        m=200;
        get_suf();
        printf("%lld\n",solve(len1,k));
    }
    return 0;
}
相關文章
相關標籤/搜索