考研路茫茫——单词情结
这个题也是用AC自动机记录状态,然后得到状态转移矩阵。
因为这道题求的是包括词根的,所以我们先得到不包括词根,然后再用总数减去即可得到。
另外需要注意的一点是,长度不超过L,这又跟之前写的那道限定长度的题不同了,需要在矩阵中再添加一列,用于求和,这一列的值全为1,通过,手推即可发现规律
此外在求总数的时候,需要求一个逆元,看到网上很普遍的求法是用矩阵快速幂来求的,但是其实这个可以直接用等比数列的求和公式直接计算,需要注意的是,它需要求一个逆元,但是他这个逆元不是\(p^{mod-2}\),因为它的模数不是质数。
// Created by CAD
#include <bits/stdc++.h>
#define ll unsigned long long
using namespace std;
typedef vector<ll> vec;
typedef vector<vec> mat;
mat operator *(mat a,mat b){
mat ans(a.size(),vec(b[0].size()));
for(int i=0;i<a.size();++i)
for(int j=0;j<b[0].size();++j)
for(int k=0;k<b.size();++k)
ans[i][j]=ans[i][j]+a[i][k]*b[k][j];
return ans;
}
mat qpow(mat x,ll n){
mat ans(x.size(),vec(x.size()));
for(int i=0;i<x.size();++i)
ans[i][i]=1;
while(n){
if(n&1) ans=ans*x;
n>>=1,x=x*x;
}
return ans;
}
ll qpow(ll x,ll n){
ll ans=1;
while(n>0){
if(n&1) ans=ans*x;
n>>=1,x=x*x;
}
return ans;
}
const int maxn=50;
namespace ac{
const int chsiz=30;
int next[maxn][chsiz],fail[maxn],end[maxn];
int root,sz;
//新建节点
int newnode(){
for(int i=0;i<chsiz;++i)
next[sz][i]=-1;
end[sz++]=0;
return sz-1;
}
//初始化
void init(){
sz=0;
root=newnode();
}
//插入字符串
void insert(char buf[]){
int len=strlen(buf);
int now=root;
for(int i=0;i<len;i++){
if(next[now][buf[i]-'a']==-1)
next[now][buf[i]-'a']=newnode();
now=next[now][buf[i]-'a'];
}
end[now]=1;
}
//构建AC自动机
void build(){
queue<int> Q;
fail[root]=root;
for(int i=0;i<chsiz;++i)
if(next[root][i]==-1)
next[root][i]=root;
else{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
//求 fail 数组
while(!Q.empty()){
int now=Q.front(); Q.pop();
end[now]|=end[fail[now]];
for(int i=0;i<chsiz;++i)
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
mat getmat(){
mat ans(sz+1,vec(sz+1,0));
for(int i=0;i<sz;++i){
for(int j=0;j<26;++j)
if(!end[next[i][j]]) ans[i][next[i][j]]++;
}
for(int i=0;i<sz+1;++i)
ans[i][sz]++;
return ans;
}
}
void print(mat &m){
for(int i=0;i<m.size();++i)
for(int j=0;j<m[i].size();++j)
cout<<m[i][j]<<" \n"[j==m[i].size()-1];
cout<<endl;
}
char buf[40];
int main() {
int n,m;
while(~scanf("%d%d",&n,&m)){
ac::init();
for(int i=1;i<=n;++i){
scanf("%s",buf);
ac::insert(buf);
}
ac::build();
mat res=ac::getmat();
res=qpow(res,m);
ll ans=0;
for(int i=0;i<ac::sz+1;++i)
ans+=res[0][i];
ans--;
ans=(qpow(26,m)-1)*26*qpow(25,(1ll<<63)-1)-ans;
cout<<ans<<endl;
}
return 0;
}
CAD加油!欢迎跟我一起讨论学习算法,QQ:1401650042