题目描述:
背了N个词根,长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?
比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
(2个) aa,ab,
(26个)aaa,aab,aac…aaz,
(26个)aba,abb,abc…abz,
(25个)baa,caa,daa…zaa,
(25个)bab,cab,dab…zab。
0
<
N
<
6
,
0
<
L
<
2
3
1
0<N<6,0<L<2^31
0<N<6,0<L<231,每个词根仅由小写字母组成,长度不超过5。
答案
m
o
d
2
64
\mod 2^{64}
mod264
题目分析:
至少包含一个即用所有单词数减去一个也不包含的单词数。
一个词根都不包含的单词数可以在AC自动机上DP得到。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示用了
i
i
i个字母,到了自动机上的
j
j
j号点的方案数。
枚举字母
c
c
c,有转移:
(
c
h
[
j
]
[
c
]
没
有
被
标
记
为
词
根
)
f
[
i
+
1
]
[
c
h
[
j
]
[
c
]
]
+
=
f
[
i
]
[
j
]
(ch[j][c]没有被标记为词根) f[i+1][ch[j][c]]+=f[i][j]
(ch[j][c]没有被标记为词根)f[i+1][ch[j][c]]+=f[i][j]
容易矩阵加速,初始矩阵
f
[
0
]
[
0
]
=
1
f[0][0]=1
f[0][0]=1,转移矩阵
g
[
i
]
[
c
h
[
i
]
[
c
]
]
+
=
1
g[i][ch[i][c]]+=1
g[i][ch[i][c]]+=1,因为长度是小于等于L,所以还要多加一个记录前缀和的位置,转移矩阵的最后一列全为1。
注意所有单词数并不是 2 6 L 26^L 26L,而是 2 6 1 + 2 6 2 + . . . + 2 6 L 26^1+26^2+...+26^L 261+262+...+26L,因为没有逆元所以同样要矩阵加速(或者递归)。
Code:
#include<bits/stdc++.h>
#define ULL unsigned long long
using namespace std;
const int maxn = 35, maxc = 26;
int n,m,ch[maxn][maxc],fail[maxn],tot,N;
bool vis[maxn];
char s[10];
struct Mat{
ULL s[35][35];
Mat(){memset(s,0,sizeof s);}
Mat operator * (const Mat &B)const{
Mat ret;
for(int k=0;k<N;k++)
for(int i=0;i<N;i++) if(s[i][k])
for(int j=0;j<N;j++)
ret.s[i][j]+=s[i][k]*B.s[k][j];
return ret;
}
}f,g;
void Clear(){memset(ch,0,maxc*(tot+1)*4),memset(vis,0,tot+1),tot=0;}
void insert(char *s){
int r=0,v;
for(int i=0;s[i];i++,r=ch[r][v])
if(!ch[r][v=s[i]-'a']) ch[r][v]=++tot;
vis[r]=1;
}
int q[maxn],L,R;
void build(){
q[L=R=0]=0;
while(L<=R){
int r=q[L++],c;
for(int i=0;i<maxc;i++)
if(c=ch[r][i]) fail[c]=r?ch[fail[r]][i]:0,vis[c]|=vis[fail[c]],q[++R]=c;
else ch[r][i]=ch[fail[r]][i];
}
}
inline Mat Pow(Mat a,int b){
Mat s;for(int i=0;i<N;i++) s.s[i][i]=1;
for(;b;b>>=1,a=a*a) if(b&1) s=s*a;
return s;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
Clear(); ULL ans=0;
for(int i=1;i<=n;i++) scanf("%s",s),insert(s);
build();
g=Mat(),N=tot+2;
for(int i=0;i<=tot+1;i++) g.s[i][tot+1]=1;
for(int i=0;i<=tot;i++)
for(int j=0;j<maxc;j++) if(!vis[ch[i][j]])
g.s[i][ch[i][j]]++;
g=Pow(g,m);
for(int i=0;i<N;i++) ans-=g.s[0][i];
g=Mat(),N=2,g.s[0][0]=26,g.s[0][1]=g.s[1][1]=1;
g=Pow(g,m);
for(int i=0;i<N;i++) ans+=g.s[0][i];
printf("%llu\n",ans);
}
}