其实,这题涉及到AC自动机的Dp
主要是利用了AC自动机能判断一个子串是否在匹配中
但是,我试写了一个,发现会多算……
{弱……}
首先我们看一个结点往后添一个字,先Fail回去,再看看打没打标记……
实际上这是错的
因为可能在更之后出现标记。
倘若将答案更之后,又会因为少了前面的信息多算。
所以要先预处理出一个结点实际有没有标记(endmark)
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #include<cmath> #include<cctype> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define ForD(i,n) for(int i=n;i;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define RepD(i,n) for(int i=n;i>=0;i--) #define MAXN (60+10) #define MAXLen (100+10) #define F (10007) int n,m,size=0; char s[MAXLen]; struct node { node *fa,*ch[26],*fail; int no,endmark; bool mark; node(int _no):no(_no),mark(0),endmark(0){fa=fail=NULL;Rep(i,26) ch[i]=NULL;} node(node *_fa,int _no):no(_no),mark(0),endmark(0){fa=_fa;fail=NULL;Rep(i,26) ch[i]=NULL;} }*root,*c[MAXN*MAXLen]; void insert(char *a) { int n=strlen(a); node *now=root; Rep(i,n) { int p=a[i]-'A'; if (now->ch[p]==NULL) { now->ch[p]=new node(now,++size); c[size]=now->ch[p]; } now=now->ch[p]; } now->mark=1; } int q[MAXN*MAXLen*10]; void getfail() { q[1]=1; int head=1,tail=1; while (head<=tail) { node *now=c[q[head]]; Rep(i,26) if (now->ch[i]) { q[++tail]=now->ch[i]->no; if (q[head]!=1) { node *p=now->fail; while (p!=root&&p->ch[i]==NULL) p=p->fail; if (p->ch[i]) now->ch[i]->fail=p->ch[i]; else now->ch[i]->fail=root; }else now->ch[i]->fail=root; if (now->ch[i]->fail!=root) now->ch[i]->endmark=now->ch[i]->fail->mark?now->ch[i]->fail->no:now->ch[i]->fail->endmark; } head++; } } int pow(int a,int b) { if (b==1) return a; if (b==0) return 1; int tmp=pow(a,b/2); tmp=tmp*tmp%F; if (b%2) tmp=tmp*a%F; return tmp; } int f[MAXLen][MAXN*MAXLen]; int main() { // freopen("bzoj1030.in","r",stdin); root=new node(++size),c[1]=root;root->fa=root->fail=root; scanf("%d%d",&n,&m); For(i,n) { scanf("%s",s);insert(s); } getfail(); memset(f,0,sizeof(f)); f[0][1]=1; Rep(i,m) For(j,size) { if (!f[i][j]) continue; Rep(k,26) { node *now=c[j]; while (now!=root&&now->ch[k]==NULL) now=now->fail; if (now->ch[k]==NULL) f[i+1][1]=(f[i+1][1]+f[i][j])%F; else { now=now->ch[k]; if (now->mark||now->endmark) continue; f[i+1][now->no]=(f[i+1][now->no]+f[i][j])%F; } } } int ans=0; // cout<<size<<endl; For(j,size) ans=(ans+f[m][j])%F/*,cout<<ans<<' '*/; // cout<<ans<<endl; ans=(pow(26,m)-ans+F)%F; printf("%d\n",ans); return 0; }