zoj 3587 Marlon's String

有两个字符串A和B,求多少对属于A的子串组成B。

若组成B的其中一个子串等于B[0...i](0<=i<n),那么另外一个就等于B[i+1...n-1].所以总共有n-1种形式。

那么其实就是求B[0...i]和B[i+1...n-1]的值,之后再利用乘法原理求出答案。

既然是两个串的模式匹配,KMP算法就再适合不过了。

KMP算法的核心在于p[]数组,p[i]指的是s[0...p[i]]等于s[i-p[i]...i]。

 

#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAXN 100010
using namespace std;

int p[MAXN];
char str[MAXN],s[MAXN];
long long a[MAXN],b[MAXN];

void getNext(char *s,int *p)
{
int i,j;
j=p[0]=-1;
for(i=1;s[i]!='\0';i++)
{
p[i]=-1;
while(j>-1&&s[j+1]!=s[i])
j=p[j];
if(s[j+1]==s[i])
{
j++;
p[i]=j;
}
}
}

int main()
{
int i,j,t,n,m;
long long ans;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",str,s);
getNext(s,p);
m=strlen(str);
n=strlen(s);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
ans=0;
for(i=0,j=-1;i<m;i++)
{
while(j>-1&&s[j+1]!=str[i])
j=p[j];
if(s[j+1]==str[i])
{
j++;
a[j]++;
}
}
for(i=n-1;i>0;i--)
if(p[i]>-1)
a[p[i]]+=a[i];

for(i=0;i+i<m;i++)
swap(str[i],str[m-1-i]);
for(i=0;i+i<n;i++)
swap(s[i],s[n-1-i]);

getNext(s,p);
for(i=0,j=-1;i<m;i++)
{
while(j>-1&&s[j+1]!=str[i])
j=p[j];
if(s[j+1]==str[i])
{
j++;
b[j]++;
}
}
for(i=n-1;i>0;i--)
if(p[i]>-1)
b[p[i]]+=b[i];

for(i=0;i+1<n;i++)
ans+=a[i]*b[n-2-i];

printf("%lld\n",ans);
}
return 0;
}

 

posted @ 2012-03-27 17:08    阅读(429)  评论(0编辑  收藏  举报