• 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;
    }
  • 相关阅读:
    数字基本数据类型范围比较
    java中float和double的区别
    ASP.NET中javascript与c#互相访问
    Javascript技术之详尽解析event对象
    Java基础-Java中的Calendar和Date类
    逻辑运算符
    JS获取当前时间
    几秒后刷新页面
    【LiteOS】LiteOS任务篇源码分析删除任务函数
    POJ 2385 Apple Catching (DP)
  • 原文地址:https://www.cnblogs.com/algorithms/p/2628828.html
Copyright © 2020-2023  润新知