传送门!c++
感受AC自动机套dp的题还挺套路的,,,ide
通常就先跑遍AC自动机,而后就用dp优化
dp的状态通常都是f[i][j]:有i个字符,是ac自动机上的第j个节点,而后有的题目可能还要加一维用来知足一些额外要求之类的spa
而后据说矩阵优化dp挺常见的,,,但我还没作过这种题QAQcode
而后这题就直接很套路啊,,,直接上面那种套路一点修改都没有,,,blog
就显然答案是全部状态-非法状态get
全部状态就26mit
非法状态就上面那个套路算下event
而后就作完了呢,,,class
放下代码趴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; }