zoukankan      html  css  js  c++  java
  • HDOJ 2243 考研路茫茫——单词情结(自动机DP+矩阵快速幂和)

    题意:给出N个词根,求长不超过L的且至少包含一个上述词根的单词的个数。

    数据范围:0<N<6,0<L<2^31

    这题与上一题差不多,但比上题要繁琐的多,关键的区别在于"不超过L" 和"至少包含一个"

    因为"至少包含一个",所以刚好是求上一题的反面;

    因为"不超过L",所以要求的是矩阵幂和S = A + A2 + A3 + … + Ak

    View Code
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    #include <math.h>
    using namespace std;
    
    #define N 6
    #define LEN 6
    #define SIZE (N*LEN)
    typedef unsigned __int64 LL;
    int n,l,node;
    int next[SIZE][26];
    int fail[SIZE];
    bool isend[SIZE];
    
    LL mat[SIZE][SIZE];
    LL ans[SIZE][SIZE];
    
    void mat_add(LL a[][SIZE],LL b[][SIZE])
    {
        for(int i=0;i<node;i++)
        {
            for(int j=0;j<node;j++) a[i][j]+=b[i][j];
        }
    }
    void mat_mul(LL a[][SIZE],LL b[][SIZE])
    {
        LL tmp[SIZE][SIZE];
        for(int i=0;i<node;i++)
        {
            for(int j=0;j<node;j++)
            {
                tmp[i][j]=0;
                for(int k=0;k<node;k++) tmp[i][j]+=a[i][k]*b[k][j];
            }
        }
        memcpy(a,tmp,sizeof(mat));
    }
    void mat_pow(LL a[][SIZE],LL b[][SIZE],int k)
    {
        memset(a,0,sizeof(mat));
        for(int i=0;i<node;i++) a[i][i]=1;
    
        LL mm[SIZE][SIZE];
        memcpy(mm,b,sizeof(mat));
        while(k)
        {
            if(k&1)
            {
                mat_mul(a,mm);
            }
            k>>=1;
            mat_mul(mm,mm);
        }
    }
    void pow_sum(LL a[][SIZE],LL b[][SIZE],int k)
    {
        if(k==1)
        {
            memcpy(a,b,sizeof(mat));
            return;
        }
        LL c[SIZE][SIZE],d[SIZE][SIZE];
        pow_sum(a,b,k>>1);
        memcpy(d,a,sizeof(mat));
        mat_pow(c,b,k>>1);
        mat_mul(a,c);
        mat_add(a,d);
        if(k&1)
        {
            mat_mul(c,c);
            mat_mul(c,b);
            mat_add(a,c);
        }
    }
    void init()
    {
        node=1;
        memset(next[0],0,sizeof(next[0]));
    }
    void add(int cur,int k)
    {
        memset(next[node],0,sizeof(next[node]));
        isend[node]=0;
        next[cur][k]=node++;
    }
    void insert(char *s)
    {
        int i,cur,k;
        for(i=cur=0;s[i];i++)
        {
            k=s[i]-'a';
            if(!next[cur][k])   add(cur,k);
            cur=next[cur][k];
        }
        isend[cur]=1;
    }
    void get_fail()
    {
        queue<int>q;
        int cur,nxt,tmp;
    
        fail[0]=0;
        q.push(0);
    
        while(!q.empty())
        {
            cur=q.front(),q.pop();
            for(int k=0;k<26;k++)
            {
                nxt=next[cur][k];
                if(nxt)
                {
                    if(!cur)    fail[nxt]=0;
                    else
                    {
                        for(tmp=fail[cur];tmp && !next[tmp][k];tmp=fail[tmp]);
                        fail[nxt]=next[tmp][k];
                    }
                    if(isend[fail[nxt]]) isend[nxt]=1;
                    q.push(nxt);
                }
                else    next[cur][k]=next[fail[cur]][k];
            }
        }
    }
    void get_mat()
    {
        memset(mat,0,sizeof(mat));
        for(int i=0;i<node;i++)
        {
            if(isend[i])    continue;
            for(int k=0;k<26;k++)
            {
                int j=next[i][k];
                if(!isend[j])   mat[i][j]++;
            }
        }
    }
    void solve()
    {
        get_fail();
        get_mat();
    
        pow_sum(ans,mat,l);
        LL ret=0;
        for(int i=0;i<node;i++) ret-=ans[0][i];
    
        mat[0][0]=26;
        node=1;
        pow_sum(ans,mat,l);
        ret+=ans[0][0];
        printf("%I64u\n",ret);
    }
    int main()
    {
        char s[LEN];
        while(~scanf("%d%d",&n,&l))
        {
            init();
            for(int i=0;i<n;i++)
            {
                scanf("%s",s);
                insert(s);
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    C#数组添加元素
    C#数组排序方法
    C#遍历数组
    C#动态数组ArrayList
    C#传递数组参数
    基础题(四)
    基础题(三)
    CMDB概述(二)
    CMDB概述(一)
    Django(基础篇)
  • 原文地址:https://www.cnblogs.com/algorithms/p/2628828.html
Copyright © 2011-2022 走看看