zoj2587 Marlon's String

1 篇文章 0 订阅

KMP

求子串的每个前缀在母串中出现的次数,然后反转再求一次,然后计算结果即可

PS:ZOJ评测好严格啊,不强制转换类型会WA。。。就因为这个WA了好久。。。一定不要偷懒啊!!!

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>

#define N 100050

using namespace std;

int jump[N],ans1[N],ans2[N];
char s1[N],s2[N],t1[N],t2[N];

void init(char *t)
{
    jump[0]=-1;
    int j=-1,len=strlen(t);
    for(int i=1;i<len;i++)
    {
        while(j>-1&&t[i]!=t[j+1])j=jump[j];
        if(t[i]==t[j+1])j++;
        jump[i]=j;
    }
}
void kmp(char *s,char *t)
{
    int j=-1,len=strlen(s),len2=strlen(t);
    for(int i=0;i<len;i++)
    {
        while(j>-1&&s[i]!=t[j+1])j=jump[j];
        if(s[i]==t[j+1]){j++;ans1[j]++;}
        //if(j==len2-1)
        //{
           // printf("%d\n",i-len2+1);
        //}
    }
}
void kmp2(char *s,char *t)
{
    int j=-1,len=strlen(s),len2=strlen(t);
    for(int i=0;i<len;i++)
    {
        while(j>-1&&s[i]!=t[j+1])j=jump[j];
        if(s[i]==t[j+1]){j++;ans2[j]++;}
        //if(j==len2-1)
        //{
           // printf("%d\n",i-len2+1);
        //}
    }
}
int main()
{
    int tc,len1,len2;
    long long ans;
    scanf("%d",&tc);
    getchar();
    while(tc>0)
    {
       tc--;
       memset(ans1,0,sizeof(ans1));
       memset(ans2,0,sizeof(ans2));
       gets(s1);
       gets(s2);
       len1=strlen(s1),len2=strlen(s2);
       init(s2);
       kmp(s1,s2);
       for(int i=len2-1;i>=0;i--)if(jump[i]!=-1)ans1[jump[i]]+=ans1[i];                     //这个要注意
       t1[len1]='\0';t2[len2]='\0';
       for(int i=len1-1;i>=0;i--)t1[len1-i-1]=s1[i];
       for(int i=len2-1;i>=0;i--)t2[len2-i-1]=s2[i];
       init(t2);
       kmp2(t1,t2);
       for(int i=len2-1;i>=0;i--)if(jump[i]!=-1)ans2[jump[i]]+=ans2[i];                     //这个要注意
       ans=0;
       //for(int i=0;i<len2;i++)printf("%d\n",ans1[i]);
       //cout<<endl;
       //for(int i=0;i<len2;i++)printf("%d\n",ans2[i]);
       for(int i=0;i<len2-1;i++)ans+=(long long)ans1[i]*(long long)ans2[len2-i-2];          //一定要强制类型转换啊,切记!!
       printf("%lld\n",ans);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值