题意 :  长度不超过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。

分析 : 这题和 POJ 2778 非常相似,如果没有做过 POJ 2778 建议先去搞定那道题。此题难点就在于这个是要求不超过 L 长度包含词根的单词,根据解决 POJ 2778 的经验,我们可以得出  答案 = 总单词种类数 - 不包含词根的单词数。首先总单词数可以很容易想到为 261 + 262 + 263 + ..... + 26L ,而不包含词根的单词总数可以这样得到 ==> 假设原 Trie 图构建出来的状态矩阵为 A ,那么同样的我们需要构造一个幂和即 A1 + A2 + A3 + ..... + AL 然后最后的答案便是 ∑AL(0, i)  ( i ∈ 1~矩阵长度 ) ,那怎么去构造这两个幂和呢?

只要利用这个公式即可,用原矩阵 + 单位矩阵 + 零矩阵构造出新矩阵,最后右上角的矩阵便是幂和的矩阵!

这里还有一点要注意,就是对于 2^64次方求模有一个很巧的方法,也就是直接定义为 unsigned long long (范围 : 0 ~ 2^64 -1),溢出就相当于求模了!

#include<string.h>
#include<stdio.h>
#include<iostream>
#include<queue>
#define ULL unsigned long long
using namespace std;

;
;
int maxn;///矩阵的大小
];

][]; }unit, M;
mat operator * (mat a, mat b){
    mat ret;
    ; i<maxn; i++){
        ; j<maxn; j++){
            ret.m[i][j] = (ULL);
            ; k<maxn; k++){
                ret.m[i][j] += a.m[i][k]*b.m[k][j];
            }
        }
    }
    return ret;
}

inline void init_unit() {
    ; i<maxn; i++)
        unit.m[i][i] = ;
}

mat pow_mat(mat a, long long n){
    mat ret = unit;
    while(n){
        ) ret = ret * a;
        a = a*a;
        n >>= ;
    }
    return ret;
}

struct Aho{
    struct StateTable{
        int Next[Letter];
        int fail, flag;
    }Node[Max_Tot];
    int Size;
    queue<int> que;

    inline void init(){
        while(!que.empty()) que.pop();
        memset(Node[].Next, , ].Next));
        Node[].fail = Node[].flag = ;
        Size = ;
    }

    inline void insert(char *s){
        ;
        ; s[i]; i++){
            int idx = s[i] - 'a';
            if(!Node[now].Next[idx]){
                memset(Node[Size].Next, , sizeof(Node[Size].Next));
                Node[Size].fail = Node[Size].flag = ;
                Node[now].Next[idx] = Size++;
            }
            now = Node[now].Next[idx];
        }
        Node[now].flag = ;
    }

    inline void BuildFail(){
        Node[].fail = -;
        ; i<Letter; i++){
            ].Next[i]){
                Node[Node[].Next[i]].fail = ;
                que.push(Node[].Next[i]);
            }].Next[i] = ;///必定指向根节点
        }
        while(!que.empty()){
            int top = que.front(); que.pop();
            ;
            ; i<Letter; i++){
                int &v = Node[top].Next[i];
                if(v){
                    que.push(v);
                    Node[v].fail = Node[Node[top].fail].Next[i];
                }else v = Node[Node[top].fail].Next[i];
            }
        }
    }

    inline void BuildMatrix(){
        ; i<Size; i++)
            ; j<Size; j++)
                M.m[i][j] = ;
        ; i<Size; i++){
            ; j<Letter; j++){
                if(!Node[i].flag && !Node[ Node[i].Next[j] ].flag)
                    M.m[i][Node[i].Next[j]]++;
            }
        }
        maxn = Size;
    }
}ac;

ULL GetSum(long long num){
    mat ret;
    ret.m[][] = ;
    ret.m[][] = ;
    ret.m[][] = ;
    ret.m[][] = ;
    int tmp = maxn;
    maxn = ;
    ret = pow_mat(ret, ++num);
    maxn = tmp;
    ][]-;
}

ULL GetElimination(long long num){
    mat tmp;
    ; i<maxn; i++)///左上角 为 原矩阵
        ; j<maxn; j++)
            tmp.m[i][j] = M.m[i][j];

    ; i<maxn; i++)///右上角 为 单位矩阵
        ); j++)
            tmp.m[i][j] = (i+maxn == j);

    ); i++)///左下角 为 零矩阵
        ; j<maxn; j++)
            tmp.m[i][j] = ;

    ); i++)///右下角 为 单位矩阵
        ); j++)
            tmp.m[i][j] = (i==j);

    int Temp = maxn;
    maxn <<= ;///先将原本矩阵的大小放大一倍进行快速幂运算,这个和我快速幂的写法有关
    tmp = pow_mat(tmp, ++num);
    ULL ret = (ULL);
    maxn = Temp;///再回复成原来大小
    ); i++)///右上角的矩阵就是幂和了
        ret += tmp.m[][i];

    return (--ret);///需要 -1
}

int main(void)
{
    int n, m;

    while(~scanf("%d %d", &m, &n)){
        ac.init();
        ; i<m; i++){
            scanf("%s", S);
            ac.insert(S);
        }
        ac.BuildFail();
        ac.BuildMatrix();
        init_unit();
        ULL Tot = GetSum((long long)n);///注意是传long long不然会爆int
        ULL Elimination = GetElimination((long long)n);
        cout<<Tot-Elimination<<endl;
    }
    ;
}

HDU 2243 考研路茫茫——单词情结 ( Trie图 && DP && 矩阵构造幂和 )的更多相关文章

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

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

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

    和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_ ...

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

    http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意: 给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数. 思路: 如果做过poj2778 ...

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

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

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

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

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

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. HDU 2243 考研路茫茫——单词情结

    考研路茫茫——单词情结 Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID ...

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

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <23 ...

  9. HDU 2243 考研路茫茫——单词情结 求长度小于等于L的通路总数的方法

    http://acm.hdu.edu.cn/showproblem.php?pid=2243 这是一题AC自动机 + 矩阵快速幂的题目, 首先知道总答案应该是26^1 + 26^2 + 26^3 .. ...

随机推荐

  1. 【MM系列】SAP 财务帐与后勤不一致情况

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP 财务帐与后勤不一致情况   ...

  2. Hand on Machine Learning第三章课后作业(2):其余小练习

    -#!/usr/bin/env python -# # # -- coding: utf-8 -- -# # # @Time : 2019.5.22 14:09 -# # # @Author : An ...

  3. git.ZC一套命令_稀疏签出(sparse-checkout)

    1. git init git remote add origin https://gitee.com/?????/movieHome.git git config core.sparsechecko ...

  4. Python解释器判断整数相加溢出

    溢出,则和的最高位(即符号位)与两个加数都不相同,例如 1)非负数+非负数=负数 2)负数+负数=非负数 那么,假设x为a与b的和,((a^b)>=0 && (x^a)<0 ...

  5. [转帖]mysql数据库主从配置

    mysql数据库主从配置 https://www.toutiao.com/i6680489302947791371/ 多做实验 其实挺简单的 很多东西 要提高自信 去折腾. 架构与我 2019-04- ...

  6. Linux命令(持续更新)

    1. tail 命令    tail 命令可用于查看文件的内容,有一个常用的参数 -f 常用于查阅正在改变的日志文件. tail  -f  filename 会把 filename 文件里的最尾部的内 ...

  7. php配置伪静态如何将.htaccess文件转换 nginx伪静态文件

    php通常设置伪静态三种情况,.htaccess文件,nginx伪静态文件,Web.Config文件得形式,如何将三种伪静态应用到项目中呢, 1,.htaccess文件 实例 <IfModule ...

  8. hdu1263 简单模拟

    题意:依据水果销量表.依照特定格式输出 格式:首先按产地排序,然后同一产地按水果名排序 注意:第一,设计多级排序           第二.同一产地同一水果可能多次出现,所以须要在前面已经输入的水果里 ...

  9. RabbitMQ交换器Exchange介绍与实践

    RabbitMQ交换器Exchange介绍与实践 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器Exchang ...

  10. 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构

    github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...