hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)

考研路茫茫——单词情结

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4843    Accepted Submission(s): 1527

Problem Description

背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。
一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。

于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。

比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
(2个) aa,ab,
(26个)aaa,aab,aac...aaz,
(26个)aba,abb,abc...abz,
(25个)baa,caa,daa...zaa,
(25个)bab,cab,dab...zab。

这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。

Input

本题目包含多组数据,请处理到文件结束。
每组数据占两行。
第一行有两个正整数N和L。(0<N<6,0<L<2^31)
第二行有N个词根,每个词根仅由小写字母组成,长度不超过5。两个词根中间用一个空格分隔开。

Output

对于每组数据,请在一行里输出一共可能的单词数目。
由于结果可能非常巨大,你只需要输出单词总数模2^64的值。

Sample Input

2 3

aa ab

1 2

a

Sample Output

104
52

/*
hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)

给你m个子串,求包含至少一个子串的长度不大于n的字符串的种类数
所有可能: 26+26^2 + .... + 26^n
而且前面也求过一个子串都不包含的情况。即把他们的关系转换成矩阵mat
一个都不包含的情况: mat + mat^2 +..... + mat^n
对于求 次方和.  mat+... mat^6 = mat+mat^2+mat^3 + mat^3*(mat+mat^2+mat^3)
于是求出两个的值然后减去即可

// 矩阵求a走m步到b的方案数 + A + A^2 + A^3 + ... + A^k的结果(两个矩阵的经典应用)
hhh-2016-04-23 22:33:39
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <functional>
#include <map>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef unsigned long long ll;
typedef unsigned int ul;
const int  maxn = 40010;
int tot;

struct Matrix
{
    int len;
    ll ma[50][50];
    Matrix() {}
    Matrix(int L)
    {
        len = L;
    }
};

Matrix mult(Matrix ta,Matrix tb)
{
    Matrix tc;
    tc.len = ta.len;
    for(int i = 0; i < ta.len; i++)
    {
        for(int j = 0; j < ta.len; j++)
        {
            tc.ma[i][j] = 0;
            for(int k = 0; k < ta.len; k++){
                tc.ma[i][j] = tc.ma[i][j]+(ll)ta.ma[i][k]*tb.ma[k][j];
            }
        }
    }
    return tc;
}

Matrix pow_mat(Matrix a,ll n)
{
    Matrix cnt;
    cnt.len = a.len;
    memset(cnt.ma,0,sizeof(cnt.ma));
    for(int i = 0 ; i < cnt.len; i++)
        cnt.ma[i][i] = 1;

    while(n)
    {
        if(n&1) cnt = mult(cnt,a);
        a = mult(a,a);
        n >>= 1;
    }
    return cnt;
}

Matrix Add(Matrix ta,Matrix tb)
{
    Matrix tc;
    tc.len = ta.len;
    for(int i = 0;i < tc.len;i++)
    {
        for(int j = 0;j < tc.len;j++)
        {
            tc.ma[i][j] = (ta.ma[i][j]+tb.ma[i][j]);
        }
    }
    return tc;
}

struct Tire
{
    int nex[50][26],fail[50],ed[50];
    int root,L;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            nex[L][i] = -1;
        ed[L++] = 0;
        return L-1;
    }

    void ini()
    {
        L = 0,root = newnode();
    }

    void inser(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            int ta = buf[i]-‘a‘;
            if(nex[now][ta] == -1)
                nex[now][ta] = newnode();
            now = nex[now][ta];
        }
        ed[now]  ++;
    }

    void build()
    {
        queue<int >q;
        fail[root] = root;
        for(int i = 0; i < 26; i++)
            if(nex[root][i] == -1)
                nex[root][i] = root;
            else
            {
                fail[nex[root][i]] = root;
                q.push(nex[root][i]);
            }
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            if(ed[fail[now]])
                ed[now] = 1;
            for(int i = 0; i < 26; i++)
            {
                if(nex[now][i] == -1)
                    nex[now][i] = nex[fail[now]][i];
                else
                {
                    fail[nex[now][i]] = nex[fail[now]][i];
                    q.push(nex[now][i]);
                }
            }
        }
    }

    Matrix to_mat()
    {
        Matrix mat(L);
        memset(mat.ma,0,sizeof(mat.ma));
        for(int i = 0;i < L;i++)
        {
            for(int j = 0;j < 26;j++)
            {
                if(!ed[nex[i][j]])
                    mat.ma[i][nex[i][j]] ++;
            }
        }
        return mat;
    }
};

Matrix mat;

Matrix cal(int n)
{
    if(n == 1)
        return mat;
    Matrix tp = cal(n/2);
    if(n & 1)
    {
        Matrix t = pow_mat(mat,n/2+1);
        tp = Add(tp,mult(t,tp));
        tp = Add(tp,t);
    }
    else
    {
        Matrix t = pow_mat(mat,n/2);
        tp = Add(tp,mult(t,tp));
    }
    return tp;
}

ll pow_mod(ll a,int n)
{
    ll cnt = 1;
    while(n)
    {
        if(n&1) cnt = cnt*a;
        a = a*a;
        n >>= 1;
    }
    return cnt;
}

ll ca(int n)
{
    if(n == 1)
        return 26;
    ll tp = ca(n/2);
    if(n & 1)
    {
        ll t = pow_mod(26,n/2+1);
        tp = tp+t+tp*t;
    }
    else
    {
       ll t = pow_mod(26,n/2);
       tp = tp+t*tp;
    }
    return tp;
}

Tire ac;
char buf[20];
int main()
{
    int n,m;
    while(scanf("%d%d",&m,&n) != EOF)
    {
        ac.ini();
        for(int i = 1; i <= m; i++)
        {
            scanf("%s",buf);
            ac.inser(buf);
        }
        ac.build();
        mat = ac.to_mat();
        Matrix ans = cal(n);
        ll tans = ca(n);
        ll t = 0;
        for(int i = 0;i < ans.len;i++)
        {
            t += ans.ma[0][i];
        }
        printf("%I64u\n",tans-t);
    }
    return 0;
}

  

时间: 2024-10-09 20:59:49

hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)的相关文章

hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <231)的单词中至少含有一个词根的单词个数:结果mod 264. 基础:poj 2778DNA 序列求的是给定长度不含模式串的合法串的个数:串长度相当,都到了int上界了: 1.mod 264直接使用unsigned long long自然溢出即可:说的有些含蓄..并且也容易想到是直接使用内置类型,要不然高精度的

HDU 2243 考研路茫茫――单词情结 (AC自动机 + dp)

HDU 2243 考研路茫茫――单词情结 题意:给定一些词根,如果一个单词包含有词根,则认为是有效的.现在问长度不超过L的单词里面,有多少有效的单词? 思路:这道题和POJ 2778是同样的思路.POJ 2778是要找出长度为L的单词里面有多少无效的单词.那么根据同样的方法构造矩阵,然后所有无效的单词个数为 A + A^2 + ... + A^l 个.而所有单词的个数为26 + 26^2 + - + 26^l 个.两个减一下即为答案. 矩阵连乘求和:I + A^2 + A^3 + ... + A

HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)

题目链接 错的上头了... 这题是DNA的加强版,26^1 +26^2... - A^1-A^2... 先去学了矩阵的等比数列求和,学的是第二种方法,扩大矩阵的方法.剩下就是各种模板,各种套. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include &l

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

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

Hdu 2243 考研路茫茫——单词情结 (AC自动机+矩阵)

哎哟喂,中文题...不说题意了. 首先做过POJ 2778可以知道AC自动机是可以求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用所有给的病毒串建一个AC自动机,然后将AC自动机上所有非单词节点连一个边. 离散数学中有说道,如果矩阵A 中的 [i][j] 表示 i节点通过一条边可以走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边可以走到j节点的方法数. 既然知道这个方法,我们就明确要求什么. ans= 26+26^2+26^3+

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

和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_sub(1)+solve(2)+...+solve_sub(n)).前者构造f[i]=f[i-1]*26+26然后矩阵快速幂即可(当然也可以分治的方法).后者即构造出dp矩阵p,然后计算(p^1+p^2+...+p^n),对其分治即可. 代码如下: 1 #include <stdio.h> 2 #

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

http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意: 给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数. 思路: 如果做过poj2778的话,那么这题相对来说就会容易一些. 如果直接去计算的话,情况很复杂,和poj2778一样,我们先求出不包含模式串的个数,最后只需要相减就可以. 因为这道题目长度只要不超过n就可以,所以在构造矩阵的时候需要多加一列,该列值每行全设为1(这样最后一列的值就是对上一个矩阵每一行的和,完美计算了了各种长度

Hdu 2243 考研路茫茫——单词情结 (AC自己主动机+矩阵)

哎哟喂.中文题. . .不说题意了. 首先做过POJ 2778能够知道AC自己主动机是能够求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用全部给的病毒串建一个AC自己主动机.然后将AC自己主动机上全部非单词节点连一个边. 离散数学中有说道.假设矩阵A 中的 [i][j] 表示 i节点通过一条边能够走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边能够走到j节点的方法数. 既然知道这种方法.我们就明白要求什么. ans= 26+26

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

背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不