poj 3415 Common Substrings

這題差錯查死我了。。。最後竟然是中間過程爆int了,好囧。。

思路:把a串和b串接起來,中間加個‘$’,求後綴。

            線性的遍歷h[i]數組,然後每段公共前綴大於K的區間裏的a串和b串的數量相乘即可。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define LL __int64
using std::min;
using std::reverse;
const int V=220000;
int a[V],b[V],r[V],h[V],sa[V],X[V],Y[V],st[V];
char s[V];
int len1,K,num1[V],num2[V];
int max(int x,int y)
{
    if(x<y)x=y;
    return x;
}
void calh(int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++)r[sa[i]]=i;
    for(i=0;i<n;h[r[i++]]=k)
        for(k?k--:0,j=sa[r[i]-1];a[i+k]==a[j+k];k++);
}
bool cmp(int *r,int a,int b,int le)
{
    return (r[a]==r[b]&&r[a+le]==r[b+le]);
}
void suffix(int n,int m=128)
{
    int i,j,p,*x=X,*y=Y,*t;
    for(i=0;i<m;i++)b[i]=0;
    for(i=0;i<n;i++)b[x[i]=a[i]]++;
    for(i=1;i<m;i++)b[i]+=b[i-1];
    for(i=n-1;i>=0;i--)sa[--b[x[i]]]=i;
    for(j=1,p=1;p<n;m=p,j<<=1)
    {
        p=0;
        for(i=n-j;i<n;i++)y[p++]=i;
        for(i=0;  i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;  i<m;i++)b[i]=0;
        for(i=0;  i<n;i++)b[x[y[i]]]++;
        for(i=1;  i<m;i++)b[i]+=b[i-1];
        for(i=n-1;i>=0;i--)sa[--b[x[y[i]]]]=y[i];
        for(t=x,x=y,y=t,x[sa[0]]=0,i=1,p=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    calh(n-1);
}
LL solve(int n)
{
    int i,j,tmp,s1,s2,jj;
    LL ans=0;
    num1[0]=0;//num數組統計,目前a串和b串出現的次數
    num2[0]=0;
    for(i=1,h[n+1]=0;i<=n+1;i++)
    {
        num1[i]=num1[i-1];
        num2[i]=num2[i-1];
        if(sa[i]<len1)
            num1[i]++;
        else if(sa[i]>len1&&sa[i]<n)
            num2[i]++;
        if(h[i]>h[i-1]){
            for(j=h[i-1]+1;j<=h[i];j++)//區間左邊界
               st[j]=i-1;
        }
        else if(h[i]<h[i-1]){//到達區間右邊界,求值
            jj=max(h[i]+1,K);
            for(j=h[i-1];j>= jj;j--)
            {
                s1=num1[i-1]-num1[st[j]-1];
                s2=num2[i-1]-num2[st[j]-1];
                ans+=(LL)s1*s2;
            }
        }
    }
    return ans;
}
int main()
{
    int i,j;
    while(scanf("%d",&K)!=-1&&K)
    {
        scanf("%s",s);
        len1=strlen(s);
        s[len1]='$';
        scanf("%s",s+len1+1);
        int n=strlen(s);
        if(len1>n-1-len1)
        {
            reverse(s,s+n);
            len1=n-1-len1;
        }
        for(int i=0;i<n;i++)a[i]=s[i];
        a[n]=0;
        suffix(n+1);
        printf("%I64d\n",solve(n));
    }
    return 0;
}


發佈了54 篇原創文章 · 獲贊 44 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章