思路:
AC自动机+DP+高精度
细节错误:
(1):大数加法写错
(2):滚动数组更新写错
注意:
(1):若用矩阵乘法复杂度为O(snode^3*log(M)); TLE
(2):若用矩阵乘法的复杂度为O(snode*M*N); AC
PS.函数传参时传引用会比传变量快
源代码:
/*AC代码:766ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#define INF 1e8
#define kind 50
#define MAXN 1005
#define max(a,b) (a>b?a:b)
using namespace std;
struct Node
{
int next[kind],v,fail;
}Trie[20000];
int snode;//字典树的总结点数(总状态数)
int N,M,P;
int Q[10000],head,tail;
int hash[300];
int map[105][105];
char word[15];//模式串
struct Array
{
int num[100],len;
void Init()
{
len=0;
memset(num,0,sizeof(num));
}
}dp[2][105],ans,res;
/*------------------------AC自动机模版---------------------*/
void set_node(int x)
{
memset(Trie[x].next,0,sizeof(Trie[x].next));
Trie[x].v=0;//表示是否是危险结点
Trie[x].fail=-1;
}
void Insert(char s[])
{
int i=0,pos=0,index;
while(s[i])
{
index=hash[s[i]];
if(Trie[pos].next[index]==0)
{
set_node(++snode);
Trie[pos].next[index]=snode;
}
if(Trie[pos].v)/*危险结点为其子结点不必继续(剪枝)*/
break;
pos=Trie[pos].next[index];
i++;
}
Trie[pos].v++;
}
void Find_Fail(int pre,int ith,int now)
{
if(!pre)//如果他的父节点是root,fail直接指向root
{
Trie[now].fail=0;
return;
}
int temp=Trie[pre].fail;
while(temp!=-1)
{
if(Trie[temp].next[ith]!=0)
{
Trie[now].fail=Trie[temp].next[ith];
if(Trie[Trie[temp].next[ith]].v)//注意
Trie[now].v++;
return;
}
temp=Trie[temp].fail;
}
if(temp==-1)
Trie[now].fail=0;
return;
}
void Build_AC_Fail()
{
int i,pos;
head=tail=0;
Trie[0].fail=-1;
Q[head++]=0;
while(head!=tail)
{
pos=Q[tail++];
for(i=0;i<N;i++)
{
if(Trie[pos].next[i]!=0)//存在就要去找fail指针
{
Find_Fail(pos,i,Trie[pos].next[i]);
Q[head++]=Trie[pos].next[i];
}
else//让它的next指向pos的fail的next
Trie[pos].next[i]=Trie[Trie[pos].fail].next[i];
}
}
}
/*------------------------AC自动机模版---------------------*/
void Init()
{
int i;
char s[60];
set_node(0);snode=0;
scanf("%s",s);
for(i=0;i<N;i++)
hash[s[i]]=i;
for(i=1;i<=P;i++)
{
scanf("%s",word);
Insert(word);
}
/*
for(i=0;i<N;i++)
printf("%d ",hash[s[i]]);
printf("\n");
*/
}
/*
void get_map()
{
int i,j,u;
memset(map,0,sizeof(map));
for(i=0;i<=snode;i++)
{
if(Trie[i].v) continue;
for(j=0;j<N;j++)
{
u=Trie[i].next[j];
if(Trie[u].v) continue;
map[i][u]++;
}
}
for(i=0;i<=snode;i++)
{
for(j=0;j<=snode;j++)
printf("%d ",map[i][j]);
printf("\n");
}
}
*/
void Print(Array a)
{
int i,len=a.len;
for(i=len-1;i>=0;i--)
printf("%d",a.num[i]);
printf("\n");
}
void Add(Array &a,Array &b)
{
int i,l;
//if(a.len==0) a.len=1;
//if(b.len==0) b.len=1;
res.Init();
l=max(a.len,b.len);
//printf("*%d %d %d\n",a.len,b.len,l);
res.len=l;
for(i=0;i<l;i++)
{
res.num[i]+=(a.num[i]+b.num[i]);//注意+=
res.num[i+1]+=res.num[i]/10;
res.num[i]%=10;
}
if(res.num[l]!=0) res.len++;
//Print(res);
}
void Solve()
{
int i,j,k,temp;
Build_AC_Fail();
for(i=0;i<2;i++)
{
for(j=0;j<=snode;j++)
dp[i][j].Init();
}
//get_map();
dp[0][0].len=1;
dp[0][0].num[0]=1;
int id=0;
for(i=0;i<=M-1;i++)
{
for(j=0;j<=snode;j++)
{
if(Trie[j].v) continue;
if(dp[id][j].len==0) continue;
for(k=0;k<N;k++)
{
temp=Trie[j].next[k];//化简
if(!Trie[temp].v)
{
//printf("-----\n");
//Print(dp[id][j]);
//Print(dp[id^1][temp]);
Add(dp[id^1][temp],dp[id][j]);
dp[id^1][temp]=res;
//Print(dp[id^1][temp]);
}
}
}
//注意滚动更新
for(j=0;j<=snode;j++)
dp[id][j].Init();
id^=1;
}
ans.Init();
ans.len=1;
ans.num[0]=0;
for(i=0;i<=snode;i++)
{
if(Trie[i].v) continue;
Add(ans,dp[id][i]);
ans=res;
//Print(dp[id][i]);
}
Print(ans);
}
int main()
{
scanf("%d%d%d",&N,&M,&P);
Init();
Solve();
return 0;
}