做这个之前建议做一下poj 2778
这道题要求长度小于等于m的字符串包含所给串的有多少种,可以算出所有的情况然后减去不包含所给串的情况就是所求的。
大佬博客
大佬博客
矩阵里面存的是从i节点到j节点走一步共有多少种走法(不能走题目上给的字符串)。
然后将这个矩阵m次幂就可以求出走m步(长度为m的字符串)有多少种不包含做给串的字符串。小于等于m将其各个次幂加起来就好了,可以改一改矩阵一次就可以算出来。
所有情况就是26的1到m次幂加起来。
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL unsigned long long
using namespace std;
const int maxn=1e6+10;
struct zp
{
LL arr[110][110];//代表从i节点走一步到j节点有多少种走法
} x;
int zlen;
zp jx(zp a,zp b)
{
zp res;
for(int i=0; i<zlen; i++)
for(int j=0; j<zlen; j++)
res.arr[i][j]=0;
for(int i=0; i<zlen; i++)
for(int j=0; j<zlen; j++)
for(int k=0; k<zlen; k++)
res.arr[i][j]=res.arr[i][j]+a.arr[i][k]*b.arr[k][j];
return res;
}
zp jk(zp a,int b)
{
zp res;
for(int i=0; i<zlen; i++)
for(int j=0; j<zlen; j++)
res.arr[i][j]=(i==j);
while(b)
{
if(b&1)
res=jx(res,a);
a=jx(a,a);
b>>=1;
}
return res;
}
struct AC
{
int node[maxn][26];
int fail[maxn],cont,root,flag[maxn];
int newnode()
{
for(int i=0; i<26; i++)
node[cont][i]=-1;
flag[cont++]=0;
return cont-1;
}
void init()
{
cont=0;
root=newnode();
}
void build(char a[])
{
int len=strlen(a);
int now=root;
for(int i=0; i<len; i++)
{
if(node[now][a[i]-'a']==-1)
node[now][a[i]-'a']=newnode();
now=node[now][a[i]-'a'];
}
flag[now]=1;
}
void get_fail()
{
queue<int> q;
fail[root]=root;
for(int i=0; i<26; i++)
{
if(node[root][i]==-1)
{
node[root][i]=root;
}
else
{
fail[node[root][i]]=root;
q.push(node[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0; i<26; i++)
{
if(node[now][i]==-1)
{
node[now][i]=node[fail[now]][i];
if(flag[fail[node[now][i]]]==1)//当当前节点的fail指向一个单词结尾时这个单词也是不可到达的
flag[node[now][i]]=1;
}
else
{
fail[node[now][i]]=node[fail[now]][i];
q.push(node[now][i]);
if(flag[fail[node[now][i]]]==1)
flag[node[now][i]]=1;
}
}
}
}
void buildMatrix()
{
memset(x.arr,0,sizeof(x.arr));
for(int i=0; i<cont; i++)
for(int j=0; j<26; j++)
if(flag[node[i][j]]!=1&&flag[fail[node[i][j]]]!=1)
x.arr[i][node[i][j]]++;//这里加加是因为从同一个节点出发走一步可能有好几种走法
for(int i=0;i<cont+1;i++)//要求矩阵x的一到m次幂所以要在后面加一列
x.arr[i][cont]=1;
}
};
AC ac;
char s[2010];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
ac.init();
for(int i=0; i<n; i++)
{
scanf("%s",s);
ac.build(s);
}
ac.get_fail();
ac.buildMatrix();
zlen=ac.cont+1;
x=jk(x,m);
LL ans=0;
for(int i=0;i<zlen;i++)
ans+=x.arr[0][i];
x.arr[0][0]=26,x.arr[0][1]=1;//矩阵求26^1+26^2......26
x.arr[1][0]=0,x.arr[1][1]=1;
zlen=2;
x=jk(x,m);
ans=x.arr[0][0]+x.arr[0][1]-ans;
printf("%llu\n",ans);
}
}

本文介绍了一种使用AC自动机和矩阵快速幂的方法来计算长度小于等于m的字符串中不包含特定模式串的数量。通过构建AC自动机并结合矩阵运算,可以高效地解决这一问题。
532

被折叠的 条评论
为什么被折叠?



