HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
与POJ2778一样。这题是求长度不超过n且包含至少一个词根的单词总数。
长度不超过n的单词总数记为Sn,长度不超过n不包含词根的单词总数记为Tn。
答案就是,Sn-Tn。
Sn=26+262+263+...+26n
Tn=A+A2+A3+...+An (A为AC自动机构造出来的矩阵)
可以构造矩阵用快速幂求出Sn和Tn:
$$ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} \times \begin{bmatrix} S_n \\ 26 \end{bmatrix} = \begin{bmatrix} S_{n+1} \\ 26 \end{bmatrix}$$
$$ \begin{bmatrix} A & E \\ 0 & E \end{bmatrix} \times \begin{bmatrix} T_n \\ A \end{bmatrix} = \begin{bmatrix} T_{n+1} \\ A \end{bmatrix}$$
通过 $ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} ^n \times \begin{bmatrix} S_0 \\ 26 \end{bmatrix} = \begin{bmatrix} S_n \\ 26 \end{bmatrix}$ 即可得到Sn,其中S0=0,Tn同理。
另外题目结果mod 264这个直接把变量定义为unsigned __int64即可,溢出位数自动舍去。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int tn,ch[][],fail[];
bool flag[];
void insert(char *s){
int x=;
for(int i=; s[i]; ++i){
int y=s[i]-'a';
if(ch[x][y]==) ch[x][y]=++tn;
x=ch[x][y];
}
flag[x]=;
}
void init(int x){
memset(fail,,sizeof(fail));
queue<int> que;
for(int i=; i<; ++i){
if(ch[][i]) que.push(ch[][i]);
}
while(!que.empty()){
int x=que.front(); que.pop();
for(int i=; i<; ++i){
if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
else ch[x][i]=ch[fail[x]][i];
flag[ch[x][i]]|=flag[ch[fail[x]][i]];
}
}
}
void init(){
memset(fail,,sizeof(fail));
queue<int> que;
for(int i=; i<; ++i){
if(ch[][i]) que.push(ch[][i]);
}
while(!que.empty()){
int now=que.front(); que.pop();
for(int i=; i<; ++i){
if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i];
else ch[now][i]=ch[fail[now]][i];
flag[ch[now][i]]|=flag[ch[fail[now]][i]];
}
}
}
struct Mat{
unsigned long long m[][];
int n;
};
Mat operator*(const Mat &m1,const Mat &m2){
Mat m={};
m.n=m1.n;
for(int i=; i<m.n; ++i){
for(int j=; j<m.n; ++j){
for(int k=; k<m.n; ++k) m.m[i][j]+=m1.m[i][k]*m2.m[k][j];
}
}
return m;
}
int main(){
int n,l;
char str[];
while(~scanf("%d%d",&n,&l)){
tn=;
memset(ch,,sizeof(ch));
memset(flag,,sizeof(flag));
while(n--){
scanf("%s",str);
insert(str);
}
init();
Mat se={},sm={};
se.n=sm.n=;
for(int i=; i<; ++i) se.m[i][i]=;
sm.m[][]=; sm.m[][]=; sm.m[][]=;
n=l;
while(n){
if(n&) se=se*sm;
sm=sm*sm;
n>>=;
}
unsigned long long tot=se.m[][]*; Mat te={},tm={};
te.n=tm.n=tn+<<;
for(int i=; i<te.n; ++i) te.m[i][i]=;
for(int i=; i<=tn; ++i){
tm.m[i+tn+][i+tn+]=tm.m[i][i+tn+]=;
}
for(int i=; i<=tn; ++i){
if(flag[i]) continue;
for(int j=; j<; ++j){
if(flag[ch[i][j]]) continue;
++tm.m[i][ch[i][j]];
}
}
Mat tmp=tm; tmp.n=tn+;
n=l;
while(n){
if(n&) te=te*tm;
tm=tm*tm;
n>>=;
}
Mat tmp2; tmp2.n=tn+;
for(int i=; i<=tn; ++i){
for(int j=tn+; j<te.n; ++j) tmp2.m[i][j-tn-]=te.m[i][j];
}
tmp=tmp*tmp2;
unsigned long long res=;
for(int i=; i<=tn; ++i){
res+=tmp.m[][i];
}
printf("%llu\n",tot-res);
}
return ;
}
HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)的更多相关文章
- [hdu2243]考研路茫茫——单词情结(AC自动机+矩阵快速幂)
题意:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个. 解题关键:利用补集转化的思想,先求一个词根也不包含的单词个数,然后用总的减去即可.长度不超过L需要用矩阵维数增加一倍 ...
- hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <23 ...
- HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)
题目链接 错的上头了... 这题是DNA的加强版,26^1 +26^2... - A^1-A^2... 先去学了矩阵的等比数列求和,学的是第二种方法,扩大矩阵的方法.剩下就是各种模板,各种套. #in ...
- HDU2243 考研路茫茫——单词情结 ——AC自动机、矩阵优化
题目链接:https://vjudge.net/problem/HDU-2243 考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memor ...
- hdu_2243_考研路茫茫——单词情结(AC自动机+矩阵)
题目链接:hdu_2243_考研路茫茫——单词情结 题意: 让你求包含这些模式串并且长度不小于L的单词种类 题解: 这题是poj2788的升级版,没做过的强烈建议先做那题. 我们用poj2778的方法 ...
- hdu 2243 考研路茫茫——单词情结 AC自动机 矩阵幂次求和
题目链接 题意 给定\(N\)个词根,每个长度不超过\(5\). 问长度不超过\(L(L\lt 2^{31})\),只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个? 思路 状态(AC自动 ...
- HDU-2243 考研路茫茫——单词情结(AC自动机)
题目大意:给n个单词,长度不超过L的单词有多少个包含n个单词中的至少一个单词. 题目分析:用长度不超过L的单词书目减去长度在L之内所有不包含任何一个单词的书目. 代码如下: # include< ...
- hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu2243 考研路茫茫——单词情结【AC自动机】【矩阵快速幂】
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数详解
求两个数组的交集问题可以使用 array_intersect(),array_inersect_assoc,array_intersect_key来实现,其中 array_intersect()函数是 ...
- java类的加载过程
1.类的加载顺序 (1)JVM在首次加载类时会对 静态初始化块.静态成员变量. 静态方法进行一次初始化. (2)只有在调用new方法时才会创建类的实例. (3)对象创建过程: 首先执行父类(如果有) ...
- 将JSON转成DataSet(DataTable)
方法1: /// <summary> /// 将JSON解析成DataSet只限标准的JSON数据 /// 例如:Json={t1:[{name:'数据name',type:'数据type ...
- [Effective JavaScript 笔记]第43条:使用Object的直接实例构造轻量级的字典
js对象的核心是一个字符串属性名与属性值的映射表.使用对象实现字典易如反掌,字典是可变长的字符串与值的映射集合. for...in js提供了枚举一个对象属性名的利器--for...in循环. var ...
- Unity运行时刻资源管理
原地址:http://www.cnblogs.com/88999660/archive/2013/04/03/2998157.html Unity运行时刻资源管理 ------------------ ...
- Python机器学习库scikit-learn实践
原文:http://blog.csdn.net/zouxy09/article/details/48903179 一.概述 机器学习算法在近几年大数据点燃的热火熏陶下已经变得被人所“熟知”,就算不懂得 ...
- 07 DAY 1
壮烈的一天... 第一题 本意是水题,然后写了块状数组模拟,最后发现算法错了... 然后其实快排一遍扫一遍完事... 100分 #include <cstdio> #include < ...
- error splicing file: file too large解决方法
FAT32格式的usb最大支持4G的文件,拷贝超过4G的文件需要把usb换成NTFS格式.
- 编译 uImage
编译 uImage 和测试 u-Boot - 小猪爱拱地 - 博客频道 - CSDN.NET http://blog.csdn.net/caspiansea/article/details/38057 ...
- Java for LeetCode 160 Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...