天天看点

考研路茫茫——单词情结

​​考研路茫茫——单词情结​​

这个题也是用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;
}