题目链接:点击进入
其实看起来是完全可以用矩阵做的,但是因为用到了大数的,导致内存开不下,所以用dp写了。其实dp的过程依旧就是在我们用禁止出现单词构建的trie上走m步的过程。我们定义dp[i][j]表示走过i步以后到达节点j的方案数,则状态转移应该是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的节点,并且不能是病毒节点。但是其实这样代码就不是那么好写了,其实我们可以用节点j主动的去更新它的子节点k,这样转移方程就成了dp[i][next[j][k]]+=dp[i-1][j]。要求next[j][k]不能使病毒节点。总而言之,AC自动机上的dp就是要利用我们建立的trie树以及上面的转移方式进行状态转移。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
///大数模版
struct BigInteger{
int A[25];
enum{MOD = 10000};
BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
void print(){
printf("%d", A[A[0]]);
for (int i=A[0]-1; i>0; i--){
if (A[i]==0){printf("0000"); continue;}
for (int k=10; k*A[i]<MOD; k*=10) printf("0");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int p) {return A[p];}
const int& operator [] (int p) const {return A[p];}
BigInteger operator + (const BigInteger& B){
BigInteger C;
C[0]=max(A[0], B[0]);
for (int i=1; i<=C[0]; i++)
C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
if (C[C[0]+1] > 0) C[0]++;
return C;
}
BigInteger operator * (const BigInteger& B){
BigInteger C;
C[0]=A[0]+B[0];
for (int i=1; i<=A[0]; i++)
for (int j=1; j<=B[0]; j++){
C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
}One;
const int maxn=10*10+5;
char alph[maxn];
map<char,int>h;
int getIndex(char ch)
{
return h[ch];
}
struct Trie
{
int next[maxn][maxn/2],fail[maxn],flag[maxn];
int root,L,len;
int newnode()
{
memset(next[L],-1,sizeof(next[L]));
flag[L++];
return L-1;
}
void init()
{
L=0;
root=newnode();
}
void insert(char buf[])
{
int len1=strlen(buf);
int now=root;
for(int i=0;i<len1;i++)
{
int index=getIndex(buf[i]);
if(next[now][index]==-1)
next[now][index]=newnode();
now=next[now][index];
}
flag[now]=1;
}
void build()
{
queue<int>Q;
fail[root]=root;
for(int i=0;i<len;i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty())
{
int now=Q.front();
if(flag[fail[now]])
flag[now]++;
Q.pop();
for(int i=0;i<len;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
//flag[next[now][i]]|=flag[next[fail[now]][i]];
Q.push(next[now][i]);
}
}
}
}
};
Trie ac;
char str[maxn];
BigInteger dp[maxn][maxn];
int main()
{
int n,m,p;
///freopen("in.txt","r",stdin);
One.set(1);
while(scanf("%d%d%d",&n,&m,&p)!=EOF)
{
h.clear();
scanf("%s",alph);
for(int i=0;i<strlen(alph);i++)
h[alph[i]]=i;
ac.init();
ac.len=strlen(alph);
for(int i=0;i<p;i++)
{
scanf("%s",str);
ac.insert(str);
}
ac.build();
for(int i=0;i<=m;i++)
for(int j=0;j<ac.L;j++)
dp[i][j].set(0);
dp[0][0].set(1);
for(int i=1;i<=m;i++)
for(int j=0;j<ac.L;j++)
for(int k=0;k<n;k++)
{
if(ac.flag[ac.next[j][k]]) continue;
dp[i][ac.next[j][k]]=dp[i][ac.next[j][k]]+dp[i-1][j];
}
BigInteger ans;
ans.set(0);
for(int i=0;i<ac.L;i++)
ans=ans+dp[m][i];
ans.print();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-31 08:21:30