您的位置:首页 > 其它

【KMP】ZOJ 3587

2012-03-13 00:55 441 查看
利用了kmp的性质,kmp可以找出前i个在主串出现的次数(可覆盖),同样也可以找出后j个在主串出现的次数,只需要反向kmp就行了==,具体实现是两次预处理正向&反向,然后记录num1和num2数组

所以复杂度是线性时间.....理解kmp是重点!

#define N 100005
char s
,t
;
int next1
,next2
;
int num1
,num2
;//记录i左边在主串出现次数和i右边的
int l1,l2;
void gao1(){
int i,j=-1;
next1[0] = -1;
for(i=1;i<l2;i++){
while(j>=0 && t[i]!=t[j+1]){
j = next1[j];
}
if(t[i]==t[j+1])j++;
next1[i] = j;
}
}
void gao2(){
int i,j = l2;
next2[l2-1] = l2;
for(i=l2-2;i>=0;i--){
while(j<l2 && t[i]!=t[j-1]){
j = next2[j];
}
if(t[i]==t[j-1])j--;
next2[i] = j;
}
}
void gaogao(){
int i,j = -1;
for(i=0;i<l1;){
if(s[i]==t[j+1]){
num1[j+1]++;
i++,j++;
} else {
if(j!=-1){
j = next1[j];
} else i++;
}
}
for(i=l2-1;i>=0;i--){
if(num1[i]){
if(next1[i]!=-1){
num1[next1[i]]+=num1[i];
}
}
}
///////////////////////////////////////////////////////
j = l2;
for(i=l1-1;i>=0;){
if(s[i]==t[j-1]){
num2[j-1]++;
i--,j--;
} else {
if(j!=l2){
j = next2[j];
} else i--;
}
}
for(i=0;i<l2;i++){
if(num2[i]){
if(next2[i]!=l2){
num2[next2[i]] += num2[i];
}
}
}
}
int main(){
int ca;
scanf("%d",&ca);
while(ca--){
scanf("%s%s",s,t);
int i,j;
l1 = strlen(s);
l2 = strlen(t);
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
gao1();
gao2();
gaogao();
LL ans = 0;
for(i=0;i+1<l2;i++){
ans += (LL)num1[i]*(LL)num2[i+1];
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: