POJ 3415 Common Substrings (求长度大于K的公共子串个数,5级)

D - Common Substrings
Crawling in process... Crawling failed Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Appoint description:

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
 
   
思路:
#include<iostream>
#include<cstring>
#include<cstdio>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define clr(f,z) memset(f,z,sizeof(f))
using namespace std;
const int msize=2e5+9;
class SUFFIX_ARRAY
{
public:
  int sa[msize],h[msize],rank[msize],t1[msize],c[msize];
  bool cmp(int*r,int i,int k)
  {
    return r[ sa[i] ]==r[ sa[i-1] ]&&r[ sa[i]+k ]==r[ sa[i-1]+k ];
  }
  void build_SA(int*s,int n,int m)
  { int*wx=t1,*wy=rank;
    FOR(i,0,m-1)c[i]=0;
    FOR(i,0,n-1)++c[ wx[i]=s[i] ];
    FOR(i,1,m-1)c[i]+=c[i-1];
    for(int i=n-1;i>=0;--i)sa[ --c[ wx[i] ] ]=i;
    for(int k=1;k<=n;k<<=1)
    {
      int p=0;
      FOR(i,n-k,n-1)wy[p++]=i;
      FOR(i,0,n-1)if(sa[i]>=k)wy[p++]=sa[i]-k;
      FOR(i,0,m-1)c[i]=0;
      FOR(i,0,n-1)++c[ wx[ wy[i] ] ];
      FOR(i,1,m-1)c[i]+=c[i-1];
      for(int i=n-1;i>=0;--i)sa[ --c[ wx[ wy[i] ] ] ]=wy[i];
      swap(wx,wy);
      wx[ sa[0] ]=0;p=1;
      FOR(i,1,n-1)wx[ sa[i] ]=cmp(wy,i,k)?p-1:p++;
      if(p>=n)break;
      m=p;
    }
  }
  void get_H(int*s,int n)
  {
    int k=0;
    FOR(i,0,n)rank[ sa[i] ]=i;
    FOR(i,0,n-1)
    {
      if(k)--k;
      int j=sa[ rank[i]-1 ];
      while(s[i+k]==s[j+k])++k;
      h[ rank[i] ]=k;
    }
  }
  void debug(int n)
  {
    printf("sa=");
    FOR(i,0,n)printf("%d ",sa[i]);puts("");
    printf("rank=");
    FOR(i,0,n)printf("%d ",rank[i]);puts("");
    printf("h=");
    FOR(i,0,n)printf("%d ",h[i]);puts("");
  }
};
SUFFIX_ARRAY ty;
int len;
int r[msize];
char s1[msize],s2[msize];
int sta[msize],stb[msize];
int main()
{
  while(scanf("%d",&len)&&len)
  {
    scanf("%s%s",s1,s2);
    int len1=strlen(s1);
    int len2=strlen(s2);
    int len3=0;
    for(int i=0;s1[i];++i)
      r[i+len3]=s1[i];
    r[len3+len1]=128;
    len3+=len1+1;
    for(int i=0;s2[i];++i)
      r[ i+len3 ]=s2[i];
    r[ len3+len2 ]=129;
    len3+=len2+1;
    r[len3]=0;
    ty.build_SA(r,len3+1,300);
    ty.get_H(r,len3);
   // ty.debug(len3-1);
     long long ans=0;
        long long ss=0;
        int top=0;
        for(int i=2;i<=len3;i++)
        {
            if(ty.h[i]<len)
            {
                ss=0;
                top=0;
                continue;
            }
            int cnt=0;
            if(ty.sa[i-1]<len1)
            {
                cnt++;
                ss+=ty.h[i]-len+1;
            }
            while(top>0 && ty.h[i]<=sta[top-1])
            {
                top--;
                ss-=stb[top]*(sta[top]-ty.h[i]);
                cnt+=stb[top];
            }
            sta[top]=ty.h[i];stb[top++]=cnt;
            if(ty.sa[i]>len1)ans+=ss;
        }
        ss=0;top=0;
        for(int i=2;i<=len3;i++)
        {
            if(ty.h[i]<len)
            {
                ss=0;
                top=0;
                continue;
            }
            int cnt=0;
            if(ty.sa[i-1]>len1)
            {
                cnt++;
                ss+=ty.h[i]-len+1;
            }
            while(top>0 && ty.h[i]<=sta[top-1])
            {
                top--;
                ss-=stb[top]*(sta[top]-ty.h[i]);
                cnt+=stb[top];
            }
            sta[top]=ty.h[i];stb[top++]=cnt;
            if(ty.sa[i]<len1)ans+=ss;
        }
        printf("%I64d\n",ans);
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值