[AC自动机] HDU2243 考研路漫漫--单词情结

来源:互联网 发布:网络大学报名流程 编辑:程序博客网 时间:2024/05/22 11:46

[(http://acm.hdu.edu.cn/showproblem.php?pid=2243)]

我觉得很不错的一道AC自动机

首先把题目转换为求不含词根的数量
考虑构造一个矩阵mat[i][j]表示状态i到状态j走一步的数量
其中i和j必须要是合法状态
设s1=26^1+26^2+…+26^L,s2=mat^1+mat^2+…+mat^L
则答案等于s1-s2

mat可以由ac自动机辅助构造

注意s2的求法 可以看这个blog
[(http://www.cnblogs.com/ftae/p/7351524.html)]

#include<cstdio>#include<cstring>using namespace std;typedef unsigned long long ULL;int N;char S[6];int Tot,Son[30][26];bool Can[30];int Fail[30],Q[30];ULL L,Mat[65][65],Tmp[65][65],Ans[65][65],Base[65][65];void Insert(){    int i,u=0,l=strlen(S+1),c;    for(i=1;i<=l;i++){        c=S[i]-'a';        if(!Son[u][c])            Son[u][c]=++Tot;        u=Son[u][c];    }    Can[u]=false;}void Init(){    int i;    Tot=0;    memset(Son,0,sizeof(Son));    memset(Can,true,sizeof(Can));    for(i=1;i<=N;i++){        scanf("%s",S+1);        Insert();    }}void Get_Fail(){    int i,u,v,h=0,t=1,tmp;    memset(Fail,-1,sizeof(Fail));    Q[h]=0;    while(h<t){        u=Q[h++];        for(i=0;i<26;i++)            if(v=Son[u][i]){                tmp=Fail[u];                while(tmp!=-1&&!Son[tmp][i])                    tmp=Fail[tmp];                Fail[v]=tmp==-1?0:Son[tmp][i];                Can[v]&=Can[Fail[v]];                Q[t++]=v;            }            else Son[u][i]=Fail[u]==-1?0:Son[Fail[u]][i];    }}void Get_Matrix(){    int i,j,tmp;    memset(Mat,0,sizeof(Mat));    for(i=0;i<=Tot;i++)        if(Can[i])            for(j=0;j<26;j++)                if(Can[tmp=Son[i][j]])                    Mat[i][tmp]++;    for(i=0;i<=Tot;i++)            Mat[i][i+Tot+1]=1;    for(i=Tot+1;i<=2*Tot+1;i++)            Mat[i][i]=1;}void Mul(ULL a[65][65],ULL b[65][65],int l){    int i,j,k;    memset(Tmp,0,sizeof(Tmp));    for(i=0;i<l;i++)        for(j=0;j<l;j++)            for(k=0;k<l;k++)                Tmp[i][j]+=a[i][k]*b[k][j];    memcpy(a,Tmp,sizeof(Tmp));}void Pow(ULL base[65][65],ULL n,int l){    int i;    memset(Ans,0,sizeof(Ans));    for(i=0;i<l;i++)        Ans[i][i]=1;    while(n){        if(n&1)            Mul(Ans,base,l);        Mul(base,base,l);        n>>=1;    }    memcpy(base,Ans,sizeof(Ans));}void Work(){    int i;    ULL sum=0;    Pow(Mat,L+1,2*Tot+2);    for(i=Tot+1;i<=2*Tot+1;i++)        sum+=Mat[0][i];    Base[0][0]=Base[0][1]=26,Base[1][1]=1;    Pow(Base,L-1,2);    printf("%llu\n",(Base[0][1]+Base[1][1])*26-sum+1);}int main(){    while(~scanf("%d%llu",&N,&L)){        Init();        Get_Fail();        Get_Matrix();        Work();    }    return 0;}
阅读全文
0 0
原创粉丝点击