题意 :  长度不超过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. C++:函数求数根(总算写出来了。。。。)

    [问题描述] 数根问题递归求解:输入n个正整数(输入格式中第一行为整数个数n,后续行为n个整数),输出各个数的数根.数根的定义:对于一个正整数n,我们将它的各个位相加得到一个新的数字,如果这个数字是一 ...

  2. Win10.Shift+鼠标右键_CMD(管理员)

    1.资料: 1.1.Windows10下设置Shift+右键增加cmd - wyx0712的博客 - CSDN博客.html(https://blog.csdn.net/wyx0712/article ...

  3. 第十四周总结&实验报告八

    实验八 实现一个简单的记事本操作,有菜单项的 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; impo ...

  4. PhoneGap学习网址

    官网:http://app-framework-software.intel.com/ 下载地址:http://download.csdn.net/download/haozq2012/7635951

  5. Linux环境部署Node.js

    介绍 先前在阿里云ECS上部署Node.js,碰到不少坑,都是自己不仔细造成的,所以准备再部署一遍,并记录下来.我将我的服务器重置了,这次选择的是CentOS 7.4 64位,上次的是7.2的. 使用 ...

  6. 遍历文件夹下的csv,把数据读进一张表

    import pandas as pd import os if __name__ == '__main__': Path = 'c:\checklog' dfs = [] for dir_path, ...

  7. yii日志保存机制

    一.修改yii框架的配置文件(main.php) 'log' => array( 'class' => 'CLogRouter', 'routes' => array( array( ...

  8. 【C#】获取"我的电脑"的名字,如This PC、这台计算机

    原文:[C#]获取"我的电脑"的名字,如This PC.这台计算机 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...

  9. Kibana 基本操作

    es中的索引对应mysql的数据库.类型对应mysql的表.文档对应mysql的记录.映射对应mysql的索引索引:index类型:type映射:mappings 1.创建索引在kibana的Dev ...

  10. 如何利用scrapy新建爬虫项目

    抓取豆瓣top250电影数据,并将数据保存为csv.json和存储到monogo数据库中,目标站点:https://movie.douban.com/top250 一.新建项目 打开cmd命令窗口,输 ...