HDU 6153 KMP

最终刷KMP目标就是为了挑战这道题!现在成功了恩。。。

首先,题目大意是:
给出一个字符串str1,之后给出另一个字符串str2,问,str2的后缀在str1匹配的次数*后缀当前长度是多少

首先考虑正统求前缀的KMP

要求的是有限状态自动机不停地“返回前面的值”从而进行匹配,而这道题要求自动机向后返回,直觉告诉我应该考虑反转这个字符串的可能

对于设计样例:

A B C D

A B C

来说,首先考虑匹配的具体状况:
ABC*3,BC*2,C*1。其中C出现三次

考虑倒置情况,D C B A,和C B A会发现,同样也是:C*1+CB*2+CBA*3

从而有。。。全部倒置,一发KMP,之后按照失配边统计出现数量,之后来一发加和。。。。

事后AC代码:

#include<bits/stdc++.h>
using namespace std;

const long long MAXN=1000233;
const long long MOD=1E9+7;

long long f[MAXN];
char str1[MAXN];
long long len1;
char str2[MAXN];
long long len2;
long long point[MAXN];

void init()
{
    memset(point,0,sizeof(point));
    cin>>str1>>str2;
    len1=strlen(str1);
    len2=strlen(str2);
    reverse(str1,str1+len1);
    reverse(str2,str2+len2);
    f[0]=0;f[1]=0;
    for(int i=1;i<len2;++i)
    {
        
        int j=f[i];
        while(j&&str2[i]!=str2[j])j=f[j];
        f[i+1]= str2[i]==str2[j]? j+1:0;
        
    }
    
//    cout<<str1<<endl<<str2<<endl;
}



int main()
{
    cin.sync_with_stdio(false);
    long long t;
    cin>>t;
    for(int it=0;it<t;++it)
    {
        init();
        int j=0;
        for(int i=0;i<len1;++i)
        {
            while(j&&str1[i]!=str2[j])j=f[j];
            j= str1[i]==str2[j]? j+1:0;
            if(j)point[j-1]++;
        }
        long long ans=0;
        for(int i=len2;i;i--)
        {
            
            point[f[i]-1]+=point[i-1];
            point[f[i]-1]%=MOD;
        }
        for(int i=0;i<len2;++i)
        {
            ans+=point[i]*(i+1);
            ans%=MOD;
        }
        
        cout<<ans<<endl;
    }
    
    
    return 0;
}
原文地址:https://www.cnblogs.com/rikka/p/7419269.html