[ZeroJudge b179]Cans

一、题目

传送门(可能传不进去)
在这里插入图片描述

二、解法

A C AC 自动机上 d p dp ,设 d p [ t ] [ i ] [ j ] dp[t][i][j] 表示第 t t 天字符串的长度为 i i ,在非法字符串的自动机上的点为 j j 的方案数,考虑转移:

  • 加入a-d的一个,直接枚举选哪个,然后在自动机上直接跳,需要判断转移后是否非法。
  • 删去首位,分情况讨论。如果删去后长度为 0 0 ,直接丢进回收站。
  • 如果删去后的字符串长度小于自动机上节点的深度,那么意味着会失配,跳 f a i l fail 即可。
  • 否则就不会有影响,节点位置不变,直接转移。

然后就完了,可以算一下复杂度是可以过的,下面贴代码。 Z J ZJ 登不起,蒟蒻作者就没写代码,借用一下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;
}
发布了217 篇原创文章 · 获赞 12 · 访问量 5140

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104105126
179