做這個之前建議做一下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);
}
}