zoukankan      html  css  js  c++  java
  • 考研路茫茫——单词情结

    考研路茫茫——单词情结

    这个题也是用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]<<" 
    "[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;
    }
    
  • 相关阅读:
    poj(1458)(最长公共子序列)
    二叉搜索树
    hdu1087
    poj3641(学习了)
    平年和闰年的由来。。。。
    Linux system函数返回值(转)
    VS2010单元测试(转)
    QT QTableWidget 用法总结(转)
    QT显示图片(转)
    Qt正则表达式类QRegExp(转)
  • 原文地址:https://www.cnblogs.com/CADCADCAD/p/14078546.html
Copyright © 2011-2022 走看看