一、题目
二、解法
在 自动机上 ,设 表示第 天字符串的长度为 ,在非法字符串的自动机上的点为 的方案数,考虑转移:
- 加入
a-d
的一个,直接枚举选哪个,然后在自动机上直接跳,需要判断转移后是否非法。 - 删去首位,分情况讨论。如果删去后长度为 ,直接丢进回收站。
- 如果删去后的字符串长度小于自动机上节点的深度,那么意味着会失配,跳 即可。
- 否则就不会有影响,节点位置不变,直接转移。
然后就完了,可以算一下复杂度是可以过的,下面贴代码。 登不起,蒟蒻作者就没写代码,借用一下kk303大佬的代码,在此感谢。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define oo 2000000000
#define ll long long
using namespace std;
struct node1
{
int son[4],fail,len;
bool w;
} point[1510];
char s[105],str[105];
int p,n,dp[2][103][1510];
queue<int> myqueue;
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
int len,i,j,h,k,t,num,ans1,ans2;
memset(point,0,sizeof(point));
scanf("%s%d%d",str,&p,&n);
num=0;
while (n--)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (i=0; i<len; i++)
{
if (!point[h].son[s[i]-'a'])
{
point[h].son[s[i]-'a']=++num;
point[num].len=point[h].len+1;
}
h=point[h].son[s[i]-'a'];
if (point[h].w) break;
}
point[h].w=true;
}
while (!myqueue.empty()) myqueue.pop();
for (i=0; i<4; i++)
if (point[0].son[i])
myqueue.push(point[0].son[i]);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
if (point[point[h].fail].w) point[h].w=true;
if (point[h].w) continue;
for (i=0; i<4; i++)
{
k=point[h].fail;
while (k && !point[k].son[i]) k=point[k].fail;
point[point[h].son[i]].fail=point[k].son[i];
if (!point[h].son[i])
point[h].son[i]=point[k].son[i];
else
myqueue.push(point[h].son[i]);
}
}
h=0;
len=strlen(str);
for (i=0; i<len; i++)
{
while (h && !point[h].son[str[i]-'a'])
h=point[h].fail;
h=point[h].son[str[i]-'a'];
if (point[h].w) break;
}
k=0;
memset(dp[k],0,sizeof(dp[k]));
ans1=ans2=0;
dp[k][len][h]=1;
if (point[h].w) ans2=1;
else while (p--)
{
k=1-k;
memset(dp[k],0,sizeof(dp[k]));
for (i=0; i<=num; i++)
if (!point[i].w)
for (j=1; j<=100; j++)
if (dp[1-k][j][i])
{
if (j==1)
ans1=(ans1+dp[1-k][j][i])%10007;
else if (point[i].len>j-1)
{
t=point[i].fail;
dp[k][j-1][t]+=dp[1-k][j][i];
dp[k][j-1][t]%=10007;
}
else
{
dp[k][j-1][i]+=dp[1-k][j][i];
dp[k][j-1][i]%=10007;
}
for (h=0; h<4; h++)
{
dp[k][j+1][point[i].son[h]]+=dp[1-k][j][i];
dp[k][j+1][point[i].son[h]]%=10007;
if (point[point[i].son[h]].w)
ans2=(ans2+dp[1-k][j][i])%10007;
}
}
}
printf("%d %d\n",ans1,ans2);
return 0;
}