二刷提高课,题解目录在这里— 提高课的题解目录
看了几遍终于看懂了,这边建议先复习一下KMP算法
首先清楚自己寻找的是 子串不是t 的字符串数目
当我们匹配字符串的时候,只要将模板串匹配到了自身的长度n就意味我们找到了该子串
这里要求我们字串不是t那么就是匹配不到n(所以f的第二维不能到n)
其次在这里与我们所求的匹配过程不太一样,当我们匹配时,我们所匹配的模式串
总是跳到无法后退(起点)或者找到相等才会+1,而这里我们找的是合适的字符串的数量
我们只要知道在模板串的任意一个状态我们所枚举的a~z都会对应一条边(最开始的一条)
其次这里有两个核心点:
1:状态表示为f[i][j]:长度为i的密码,与模板串匹配的最后位置为j的方案数
2: j从0开始因为kmp算法通常是以j+1来进行判断的否则会出现-1(比较麻烦)
并且i也是从0开始的,因为从起点找到最后跳的终点容易而从终点找起点较难,非法状态会一直为零所以不必担心
#include<iostream>
#include<cstring>
using namespace std;
const int N=60,mod=1e9+7;
int f[N][N],ne[N];
char p[N];
int n,m;
int main()
{
cin>>n;
cin>>p+1;
m=strlen(p+1);
for(int i=2,j=0;i<=m;i++)
{
while(j&&p[i]!=p[j+1])j=ne[j];
if(p[j+1]==p[i])j++;
ne[i]=j;
}
f[0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
for(char k='a';k<='z';k++)
{
int pr=j;
while(pr&&k!=p[pr+1])pr=ne[pr];
if(k==p[pr+1])pr++;
f[i+1][pr]=(f[i][j]+f[i+1][pr])%mod;
//意为这个位置取k能走到f[i+1][pr]这个状态
}
}
}
int res=0;
for(int i=0;i<m;i++)res=(res+f[n][i])%mod;
cout<<res;
return 0;
}