最终刷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; }