洛谷P4052 [JSOI2007]文本生成器 AC自动机+dp

正解:AC自动机+dp

解题报告:

传送门!

感觉AC自动机套dp的题还挺套路的,,,

一般就先跑遍AC自动机,然后就用dp

dp的状态一般都是f[i][j]:有i个字符,是ac自动机上的第j个节点,然后有的题目可能还要加一维用来满足一些额外要求之类的

然后听说矩阵优化dp挺常见的,,,但我还没做过这种题QAQ

然后这题就直接很套路啊,,,直接上面那种套路一点修改都没有,,,

就显然答案是所有状态-非法状态

所有状态就26m

非法状态就上面那个套路算下

然后就做完了呢,,,

放下代码趴QAQ

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define ll long long
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=1000+10,mod=10007;
int n,m,nod_cnt,as,f[N][N*10];
struct nod{int to[30],fail;bool flg;}tr[N*10];
char str[N];
queue<int>Q;

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:x;
}
il void insert(char *s)
{
    ri lth=strlen(s+1),nw=0;
    rp(i,1,lth)
    {
        if(!tr[nw].to[s[i]-'A'+1])tr[nw].to[s[i]-'A'+1]=++nod_cnt;
        nw=tr[nw].to[s[i]-'A'+1];
    }
    tr[nw].flg=1;
}
il void bfs()
{
    rp(i,1,26)if(tr[0].to[i])Q.push(tr[0].to[i]);
    while(!Q.empty())
    {
        ri nw=Q.front();Q.pop();tr[nw].flg|=tr[tr[nw].fail].flg;
        rp(i,1,26)
            if(tr[nw].to[i])Q.push(tr[nw].to[i]),tr[tr[nw].to[i]].fail=tr[tr[nw].fail].to[i];
            else tr[nw].to[i]=tr[tr[nw].fail].to[i];
    }
}
il int power(ri x,ri y){ri ret=1;while(y){if(y&1)ret=ret*x%mod;x=x*x%mod;y>>=1;}return ret;}

int main()
{
    n=read();m=read();rp(i,1,n){scanf("%s",str+1);insert(str);}bfs();
    as=power(26,m);f[0][0]=1;
    rp(i,0,m-1)
        rp(j,0,nod_cnt)
            if(!tr[j].flg)
                rp(k,1,26)
                    if(!tr[tr[j].to[k]].flg)f[i+1][tr[j].to[k]]=(f[i+1][tr[j].to[k]]+f[i][j])%mod;
    rp(i,0,nod_cnt)as=(as+mod-f[m][i])%mod;
    printf("%d\n",as);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/lqsukida/p/10649203.html