【KMP】ZOJ 3587

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

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

#define N 100005
char s[N],t[N];
int next1[N],next2[N];
int num1[N],num2[N];//记录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;
}



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值