HDU 2243 考研路茫茫——单词情结(自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243

题意:给出m个串,问有多少不大于n的串至少包含m个串中的一个?

思路:首先求出不包含m个串的长度不大于n的串的个数,也就是对应矩阵A:S=A^1+A^2+……A^n。然后就是26+26^2+26^3+……+26^n-S。

 
   






const int mod=100000;

const int N=105;





struct node

{

    int next[26],fail,flag;



    void init()

    {

        clr(next,0);

        fail=-1;

        flag=0;

    }

};



node a[N];

int e,n,m;

char s[N];







void insert(char s[])

{

    int i,k,p=0;

    for(i=0;s[i];i++)

    {

        k=s[i]-'a';

        if(a[p].next[k]==0)

        {

            a[e].init();

            a[p].next[k]=e++;

        }

        p=a[p].next[k];

    }

    a[p].flag=1;

}



queue<int> Q;



void build()

{

    Q.push(0);

    int i,j,k,p,q;

    while(!Q.empty())

    {

        k=Q.front();

        Q.pop();

        for(i=0;i<26;i++)

        {

            if(a[k].next[i])

            {

                p=a[k].next[i];

                q=a[k].fail;

                while(q!=-1&&!a[q].next[i]) q=a[q].fail;

                if(q==-1) a[p].fail=0;

                else

                {

                    a[p].fail=a[q].next[i];

                    a[p].flag|=a[a[p].fail].flag;

                }

                Q.push(p);

            }

            else

            {

                q=a[k].fail;

                while(q!=-1&&!a[q].next[i]) q=a[q].fail;

                if(q==-1) a[k].next[i]=0;

                else a[k].next[i]=a[q].next[i];

            }

        }

    }

}





u64 b[N][N],d[N][N];



void mul(u64 a[][N],u64 b[][N])

{

    int i,j,k;

    u64 c[N][N]={0};

    FOR0(k,e) FOR0(i,e) FOR0(j,e)

    {

        c[i][j]+=a[i][k]*b[k][j];

    }

    FOR0(i,e) FOR0(j,e) b[i][j]=c[i][j];

}



u64 getPow(u64 a,u64 b)

{

    u64 ans=1;

    while(b)

    {

        if(b&1) ans=ans*a;

        a=a*a;

        b>>=1;

    }

    return ans;

}



void copyMatrix(u64 A[][N],u64 B[][N])

{

    int i,j;

    FOR0(i,e) FOR0(j,e) B[i][j]=A[i][j];

}



u64 getSum(u64 a,u64 n)

{

    if(n==0) return 1;

    if(n&1) return getSum(a,n>>1)*(1+getPow(a,n/2+1));

    else return getPow(a,n)+getSum(a,n/2-1)*(1+getPow(a,n/2));

}





void initMatrix(u64 A[][N])

{

    int i,j;

    FOR0(i,e) FOR0(j,e) A[i][j]=0;

    FOR0(i,e) A[i][i]=1;

}



void getPOW(u64 A[][N],u64 B[][N],int n)

{

    initMatrix(B);

    u64 C[N][N];

    copyMatrix(A,C);

    while(n)

    {

        if(n&1) mul(C,B);

        mul(C,C);

        n>>=1;

    }

}







void addMatrix(u64 A[][N],u64 B[][N])

{

    int i,j;

    FOR0(i,e) FOR0(j,e) B[i][j]+=A[i][j];

}



void print(u64 A[][N])

{

    int i,j;

    FOR0(i,e)

    {

        FOR0(j,e) printf("%I64u ",A[i][j]);

        puts("");

    }

    puts("");

}





u64 C[N][N],D[N][N],E[N][N];



void getSum(u64 A[][N],u64 B[][N],int n)

{

    if(n==0)

    {

        initMatrix(B);

        return;

    }





    if(n&1)

    {

        getSum(A,B,n/2);

        initMatrix(C);

        getPOW(A,D,n/2+1);

        addMatrix(C,D);

        mul(D,B);

    }

    else

    {

        getSum(A,B,n/2-1);

        getPOW(A,C,n);

        initMatrix(D);

        getPOW(A,E,n/2);

        addMatrix(D,E);

        mul(E,B);

        addMatrix(C,B);

    }

}







int main()

{

    while(scanf("%d%d",&m,&n)!=-1)

    {

        a[0].init();e=1;

        int i,j,k;

        FOR0(i,m) RD(s),insert(s);

        build();

        clr(b,0);

        FOR0(i,e) if(!a[i].flag) FOR0(j,26)

        {

            k=a[i].next[j];

            if(!a[k].flag) b[i][k]++;

        }

        u64 sum=getSum(26,n),x=((u64)1)<<63;;

        getSum(b,d,n);

        FOR0(i,e) if(!a[i].flag) sum-=d[0][i];

        printf("%I64u\n",sum);

    }

    return 0;

}

 
   

  

 
  

你可能感兴趣的:(HDU)