题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1030
要统计所有能匹配到一些串的,
只需将串的总数(
26m
)减去匹配不到的就可以了
建完AC自动机后,将所有危险点标记,在AC自动机上dp
fi,j
表示匹配j个字母后到AC自动机上的点i上,不与危险串匹配的方案有多少
如果i和他的儿子x都不危险,那么
fx,j+1=fi,j+fx,j+1
(j为枚举的步数)
统计答案时把所有
fi,m
加起来,用
26m
减去就可以了
题目没给m,自己测大概要开到100左右
代码如下:
#include<cstring>
#include<ctype.h>
#include<cstdio>
#include<queue>
#define MOD 10007
using namespace std;
int n,m,cnt,ans;
int f[100020][150];
char s[1020];
inline int quick_pow(int x,int k){
int sum=1;
while(k){
if(k&1) sum=sum*x%MOD;
x=x*x%MOD;
k=k>>1;
}
return sum%MOD;
}
struct Node{
Node *ch[26],*nex;
bool b;
int num;
Node();
}*root=new Node,*pre[100020];
Node::Node():b(false),nex(NULL){
for(int i=0;i<26;i++)
ch[i]=NULL;
num=++cnt;
pre[cnt]=this;
}
queue<Node*>q;
inline void Insert(char *s){
int len=strlen(s+1);
Node *x=root;
for(int i=1;i<=len;i++){
if(!x->ch[s[i]-'A']) x->ch[s[i]-'A']=new Node;
x=x->ch[s[i]-'A'];
}
x->b=true;
}
inline void GetFail(){
for(int i=0;i<26;i++){
if(root->ch[i]) q.push(root->ch[i]),root->ch[i]->nex=root;
else root->ch[i]=root;
}
while(!q.empty()){
Node *x=q.front();q.pop();
for(int i=0;i<26;i++){
if(x->ch[i]) x->ch[i]->nex=x->nex->ch[i],q.push(x->ch[i]);
else x->ch[i]=x->nex->ch[i];
}
Node *tmp=x->nex;
while(tmp!=root && !tmp->b) tmp=tmp->nex;
if(tmp->b) x->b=true;
}
}
void dp(){
f[root->num][0]=1;
for(int k=0;k<m;k++)
for(int i=1;i<=cnt;i++){
if(pre[i]->b || !f[i][k]) continue;
for(int j=0;j<26;j++)
if(!pre[i]->ch[j]->b)
f[pre[i]->ch[j]->num][k+1]=(f[pre[i]->ch[j]->num][k+1]+f[i][k])%MOD;
}
for(int i=0;i<=cnt;i++) ans=(ans+f[i][m])%MOD;
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
Insert(s);
}
GetFail();
dp();
ans=(quick_pow(26,m)+MOD-ans)%MOD;
printf("%d",ans);
return 0;
}