hdu 2433 考研路茫茫——单词情结 ac自动机+矩阵快速幂+dp

题意:

和poj2778很像,这个是求包含病毒串的有多少个。那么我们求出不包含的在用总数相减就可以得到答案。

///对于2^64取mod 可以直接用unsigned long long

ACcode:

#include <bits/stdc++.h>
#define maxn 160
#define ll unsigned long long
using namespace std;
int m;
ll N;
char str[33];
struct Aho{
    struct state{
        int next[26];
        int fail,cnt;
    }s[maxn];
    int size;
    queue<int>q;
    void init(){
        size=1;
        for(int i=0;i<maxn;++i){
            memset(s[i].next,-1,sizeof(s[i].next));
            s[i].fail=s[i].cnt=0;
        }
        while(q.size())q.pop();
    }
    void insert(char *str){
        int n=strlen(str);
        int now=0;
        for(int i=0;i<n;++i){
            int id=str[i]-'a';
            if(s[now].next[id]==-1)
                s[now].next[id]=size++;
            now=s[now].next[id];
        }
        s[now].cnt=1;
    }
    struct Matrix{
        ll mat[maxn][maxn];
    };
    Matrix mul(Matrix a,Matrix b){
        Matrix ret;
        memset(ret.mat,0,sizeof(ret.mat));
        for(int i=0;i<size;++i)
            for(int j=0;j<size;++j)
                for(int k=0;k<size;++k)
                    ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
        return ret;
    }
    Matrix pow(Matrix a,ll k){
        Matrix ret;
        memset(ret.mat,0,sizeof(ret.mat));
        for(int i=0;i<size;++i)ret.mat[i][i]=1;
        while(k){
            if(k&1)ret=mul(ret,a);
            a=mul(a,a);
            k>>=1;
        }
        return ret;
    }
    void build(){
        s[0].fail=0;
        for(int i=0;i<26;++i)
            if(s[0].next[i]==-1)
                s[0].next[i]=0;
            else {
                s[s[0].next[i]].fail=0;
                q.push(s[0].next[i]);
            }
        while(q.size()){
            int u=q.front();q.pop();
            if(s[s[u].fail].cnt)s[u].cnt=1;
            for(int i=0;i<26;++i){
                if(s[u].next[i]==-1)
                    s[u].next[i]=s[s[u].fail].next[i];
                else {
                    s[s[u].next[i]].fail=s[s[u].fail].next[i];
                    q.push(s[u].next[i]);
                }
            }
        }
        Matrix tmp;
        memset(tmp.mat,0,sizeof(tmp.mat));
        for(int i=0;i<size;++i){
            if(s[i].cnt)continue;
            for(int j=0;j<26;++j)
                if(!s[s[i].next[j]].cnt)
                tmp.mat[i][s[i].next[j]]++;
        }
        for(int i=0;i<=size;++i)
            tmp.mat[i][size]=1;
        size++;
        tmp=pow(tmp,N);
        ll ans=0;
        for(int i=0;i<size;++i)
            ans=(ans+tmp.mat[0][i]);
        Matrix temp;
        memset(temp.mat,0,sizeof(temp.mat));
        temp.mat[0][0]=26;
        temp.mat[1][0]=temp.mat[1][1]=1;
        temp=pow(temp,N);
        ll res=0;
        for(int i=0;i<size;++i)res=(res+temp.mat[i][0]);
        cout<<res-ans<<'\12';
    }
}aho;
int main(){
    while(cin>>m>>N){
        aho.init();
        for(int i=0;i<m;++i){
            scanf("%s",str);
            aho.insert(str);
        }
        aho.build();
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值