這題差錯查死我了。。。最後竟然是中間過程爆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;
}