HDU 2243 ( Trie图 矩阵构造幂和 )
题意 : 长度不超过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。
分析: 我们可以用Tire图跑矩阵快速幂的方法,去求长度为n不包含给定单词的词为sum; 所以想到求:长度为n包含给定单词的词 的算法就是用总的方案数-长度为n不包含给定单词的词的方案数为26^n-sum; 这题的难点是求长度不超过L的方案数,就是说我们需要求 26-sum1+26^2-sum2+26^3-sum3......26^n-sumn = (26+26^2+...26^n)-(sum1+sum2+...sumn); 我们显然不是遍历求; 考虑优先算法:
假设原 Trie 图构建出来的状态矩阵为 A ,那么同样的我们需要构造一个幂和即 A1 + A2 + A3 + ..... + AL 然后最后的答案便是 ∑AL(0, i) ( i ∈ 1~矩阵长度 ) ,那怎么去构造这两个幂和呢?

只要利用这个公式即可,用原矩阵 + 单位矩阵 + 零矩阵构造出新矩阵,最后右上角的矩阵便是幂和的矩阵
需要注意的点:(1)在求(26+26^2+...26^n)的时候不能用等比数列公式去求,这样会有误差,可以用上面构造的矩阵的方法构造
| 26,1 |
|0 , 1 | 的跑矩阵快速幂
(2 对于 2^64次方求模) 直接开unsigned long long 就好
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<queue>
#define ULL unsigned long long
using namespace std; const int Max_Tot = 1e2 + ;
const int Letter = ;
int maxn;///矩阵的大小
char S[]; struct mat{ ULL m[][]; }unit, M;
mat operator * (mat a, mat b){
mat ret;
for(int i=; i<maxn; i++){
for(int j=; j<maxn; j++){
ret.m[i][j] = (ULL);
for(int k=; k<maxn; k++){
ret.m[i][j] += a.m[i][k]*b.m[k][j];
}
}
}
return ret;
} inline void init_unit() {
for(int i=; i<maxn; i++)
unit.m[i][i] = ;
} mat pow_mat(mat a, long long n){
mat ret = unit;
while(n){
if(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, , sizeof(Node[].Next));
Node[].fail = Node[].flag = ;
Size = ;
} inline void insert(char *s){
int now = ;
for(int i=; 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 = -;
for(int i=; i<Letter; i++){
if(Node[].Next[i]){
Node[Node[].Next[i]].fail = ;
que.push(Node[].Next[i]);
}else Node[].Next[i] = ;///必定指向根节点
}
while(!que.empty()){
int top = que.front(); que.pop();
if(Node[Node[top].fail].flag) Node[top].flag = ;
for(int i=; 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(){
for(int i=; i<Size; i++)
for(int j=; j<Size; j++)
M.m[i][j] = ;
for(int i=; i<Size; i++){
for(int j=; 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;
return ret.m[][]-;
} ULL GetElimination(long long num){
mat tmp;
for(int i=; i<maxn; i++)///左上角 为 原矩阵
for(int j=; j<maxn; j++)
tmp.m[i][j] = M.m[i][j]; for(int i=; i<maxn; i++)///右上角 为 单位矩阵
for(int j=maxn; j<(maxn<<); j++)
tmp.m[i][j] = (i+maxn == j); for(int i=maxn; i<(maxn<<); i++)///左下角 为 零矩阵
for(int j=; j<maxn; j++)
tmp.m[i][j] = ; for(int i=maxn; i<(maxn<<); i++)///右下角 为 单位矩阵
for(int j=maxn; j<(maxn<<); j++)
tmp.m[i][j] = (i==j); int Temp = maxn;
maxn <<= ;///先将原本矩阵的大小放大一倍进行快速幂运算,这个和我快速幂的写法有关
tmp = pow_mat(tmp, ++num);
ULL ret = (ULL);
maxn = Temp;///再回复成原来大小
for(int i=maxn; i<(maxn<<); i++)///右上角的矩阵就是幂和了
ret += tmp.m[][i]; return (--ret);///需要 -1
} int main(void)
{
int n, m; while(~scanf("%d %d", &m, &n)){
ac.init();
for(int i=; 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;
}
return ;
}
HDU 2243 ( Trie图 矩阵构造幂和 )的更多相关文章
- POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂
这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的t ...
- 考研路茫茫——单词情结 HDU - 2243 AC自动机 && 矩阵快速幂
背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...
- 考研路茫茫――单词情结 HDU - 2243(ac自动机 + 矩阵快速幂)
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU.1575 Tr A ( 矩阵快速幂)
HDU.1575 Tr A ( 矩阵快速幂) 点我挑战题目 题意分析 直接求矩阵A^K的结果,然后计算正对角线,即左上到右下对角线的和,结果模9973后输出即可. 由于此题矩阵直接给出的,题目比较裸. ...
- HDU 2254 奥运(矩阵高速幂+二分等比序列求和)
HDU 2254 奥运(矩阵高速幂+二分等比序列求和) ACM 题目地址:HDU 2254 奥运 题意: 中问题不解释. 分析: 依据floyd的算法,矩阵的k次方表示这个矩阵走了k步. 所以k ...
- hdu 3117 Fibonacci Numbers 矩阵快速幂+公式
斐波那契数列后四位可以用快速幂取模(模10000)算出.前四位要用公式推 HDU 3117 Fibonacci Numbers(矩阵快速幂+公式) f(n)=(((1+√5)/2)^n+((1-√5) ...
- HDU 2243 考研路茫茫——单词情结 ( Trie图 && DP && 矩阵构造幂和 )
题意 : 长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词, ...
- HDU 2842 (递推+矩阵快速幂)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2842 题目大意:棒子上套环.第i个环能拿下的条件是:第i-1个环在棒子上,前i-2个环不在棒子上.每个 ...
- hdu 2604 Queuing(矩阵快速幂乘法)
Problem Description Queues and Priority Queues are data structures which are known to most computer ...
随机推荐
- Python 入门之 内置模块 -- datetime模块
Python 入门之 内置模块 -- datetime模块 1.datetime模块 from datetime import datetime (1)datetime.now() 获取当前时间和日期 ...
- java使用Callable创建又返回值的线程
并发编程使我们可以将程序分为很多个分离的,相互之间独立的任务,通过使用多线程的机制,将每个任务都会有一个执行线程来单独的驱动,一个线程是 进程中一个单一顺序控制流,一个进程可以拥有多个线程,也就相当于 ...
- CRF++的使用(待更新)
1.下载CRF++(Windows和Linux两个版本) 2.目录如下: 主要用到crf_learn.exe ,crf_test.exe和libcrfpp.dll三个文件 doc文件夹:官方主页 ex ...
- echarts 给legend图例加个标题式文字设置为普通文本不可点击
legend: [ { orient: "horizontal", // 'vertical' x: "68%", // 'center' | 'left' | ...
- 使用CXF开发WebService程序的总结(三):创建webservice客户端
1.创建一个maven子工程 ws_client,继承父工程 1.1 修改父工程pom配置 <modules> <module>ws_server</module> ...
- AutoLayout and Sizeclasses讲解
iOS8和iPhone6发布已经过去蛮久了,广大的果粉终于迎来了大屏iPhone,再也不用纠结为大屏买三星舍苹果了…但是对于iOS开发人员来说,迎来了和Android开发开发一样的问题—>各种屏 ...
- 架构师必备,带你弄清混乱的JAVA日志体系!
作者:孤独烟 出处:http://rjzheng.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任 ...
- 从标准输入读取一行数组并保存(用的是字符串分割函数strtok_s() )
首先介绍字符串分割函数: char *strtok_s( char *strToken, //字符串包含一个标记或一个以上的标记. const char *strDelimit, //分隔符的设置 c ...
- 新手的Linux zcat命令示例
Zcat是一个命令行实用程序,用于查看压缩文件的内容.它将压缩文件扩展为标准输出,允许您查看内容. 分类:Linux命令操作系统 2018-08-13 00:00:00 通常,使用gzip压缩的文件可 ...
- java面向对象5--内部类
6内部类 内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. 内部类可以是静态static的,也可用public,default,protected和private修饰.(而外部顶级类 ...