hdu2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

来源:互联网 发布:sql sum over 用法 编辑:程序博客网 时间:2024/05/18 01:30

题目链接:点击打开链接

题目描述:给定一些词根,求至少含有一个词根的长度<=L的字符串有多少种?

解题思路:AC自动机+矩阵快速幂

分析:这道题目和poj2778 DNA Sequence 是一样的,如果还没做过那道题目建议先去做一下再做这道

1、首先要知道图的邻接矩阵幂的含义是什么?不知道的请看:点击打开链接

有了上述概念之后:

AC自动机本身就是一张图,AC自动机上的每个状态表示图中的一个顶点,每条经过a、b、c···的状态转移相当于图中的一条边,所以求长度为n的字符串就相当于求在图中从出发点经过n步所能到达任意顶点的方案总数,而本题所要求的是<=L的,我们只需要求邻接矩阵A的A^1+A^2+···+A^n的方案数即可

关于如何求包含词根的字符串,根据poj2778我们会求解不包含词根的字符串,只要用总的减去不包含的就可以了即:(26^1+26^2+···+26^n)-(A^1+A^2+···+A^n)

对于如何求解一个数的前n次幂的和与一个矩阵的前n次幂的和,我们可以使用矩阵快速幂

譬如:26^1+26^2+···+26^n

|1 26|    |0|

|0 26|    |1|

A^1+A^2+···+A^n

|E A| |0|

|0 A| |E|


代码如下:

#include <cstdio>#include <cstring>#include <queue>typedef unsigned long long ll;using namespace std;struct Matrix{    ll m[60][60];    int L;    Matrix(int len){        L=len;        for(int i=0;i<L;++i)            for(int j=0;j<L;++j)                m[i][j]=0;    }    Matrix operator*(const Matrix& b){        Matrix t(L);        for(int i=0;i<L;++i)            for(int j=0;j<L;++j)                for(int k=0;k<L;++k)                    t.m[i][j]+=(m[i][k]*b.m[k][j]);        return t;    }};Matrix doexpmat(Matrix a,int num){    if(num==1) return a;    Matrix x(a.L*2);    for(int i=0;i<a.L;++i) for(int j=0;j<a.L;++j) if(i==j)x.m[i][j]=1;    for(int i=a.L;i<x.L;++i) for(int j=0;j<a.L;++j) x.m[i][j]=0;    for(int i=0;i<a.L;++i) for(int j=a.L;j<x.L;++j) x.m[i][j]=a.m[i][j-a.L];    for(int i=a.L;i<x.L;++i) for(int j=a.L;j<x.L;++j) x.m[i][j]=a.m[i-a.L][j-a.L];    Matrix t(a.L*2);    for(int i=0;i<t.L;++i) t.m[i][i]=1;    num--;    while(num){        if(num&1) t=t*x;        num=num>>1;        x=x*x;    }    Matrix tt(a.L*2);    for(int i=0;i<a.L;++i) for(int j=0;j<a.L;++j) tt.m[i][j]=a.m[i][j];    for(int i=a.L;i<t.L;++i) for( int j=0;j<a.L;++j) tt.m[i][j]=a.m[i-a.L][j];    t=t*tt;    return t;}ll pows(ll a,int num){    if(num==1) return a;    Matrix x(2);    x.m[0][0]=1; x.m[0][1]=a;    x.m[1][0]=0; x.m[1][1]=a;    Matrix t(2);    t.m[0][0]=1; t.m[1][1]=1;    num--;    while(num){        if(num&1) t=t*x;        num=num>>1;        x=x*x;    }    return (t.m[0][0]+t.m[0][1])*a;}struct Trie{    int next1[30][26],fail[30];    bool end1[30];    int root,L;    int newnode(){        for(int i=0;i<26;++i) next1[L][i]=-1;        end1[L++]=false;        return L-1;    }    void init(){        L=0;        root=newnode();    }    void insertnode(char* str){        int len=strlen(str),now=root;        for(int i=0;i<len;++i){            if(next1[now][str[i]-'a']==-1)                next1[now][str[i]-'a']=newnode();            now=next1[now][str[i]-'a'];        }        end1[now]=true;    }    void build(){        fail[root]=root;        queue<int> q;        for(int i=0;i<26;++i){            if(next1[root][i]==-1)                next1[root][i]=root;            else{                fail[next1[root][i]]=root;                q.push(next1[root][i]);            }        }        while(!q.empty()){            int now=q.front();q.pop();            if(end1[fail[now]]) end1[now]=true;            for(int i=0;i<26;++i){                if(next1[now][i]==-1)                    next1[now][i]=next1[fail[now]][i];                else{                    fail[next1[now][i]]=next1[fail[now]][i];                    q.push(next1[now][i]);                }            }        }    }    Matrix getMatrix(){        Matrix t(L);        for(int i=0;i<L;++i) for(int j=0;j<26;++j)            if(!end1[next1[i][j]]) t.m[i][next1[i][j]]++;        return t;    }};int n,l;char st[10];Trie ac;int main(){    while(scanf("%d%d",&n,&l)!=EOF){        ac.init();        for(int i=0;i<n;++i){ scanf("%s",st); ac.insertnode(st); };        ac.build();        Matrix t = ac.getMatrix();        t=doexpmat(t,l);        ll ans=0;        for(int i=0;i<ac.L;++i)            ans+=t.m[0][i];        ll tmp=pows(26,l);        printf("%I64u\n",tmp-ans);    }    return 0;}


0 0
原创粉丝点击