poj 2778 AC自动机 + 矩阵快速幂

2024-04-09 15:58
文章标签 快速 矩阵 poj ac 自动机 2778

本文主要是介绍poj 2778 AC自动机 + 矩阵快速幂,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

//	poj 2778 AC自动机 + 矩阵快速幂
//
//	题目链接:
//		
//		http://poj.org/problem?id=2778
//
//	解题思路:
//
//		建立AC自动机,确定状态之间的关系,构造出,走一步
//	能到达的状态矩阵,然后进行n次乘法,就可以得到状态间
//	走n步的方法数.
//	精髓:
//		1):这个ac自动机有一些特别,根节点是为空串,然而
//	每走一步的时候,如果没法走了,这时候,不一定是回到根
//	节点,因为有可能单个的字符时病毒,这样,不是随便就能达到
//	所谓的根节点的,所以每次初始化的时候,不能是0,而应该是
//	-1.
//
//	感悟:
//
//		这道AC自动机,开始我是完全不会,知道是AC自动机+矩阵快速幂
//	开始,自以为AC自动机构造的很对,而且样例都过了好嘛,结果一直是
//	wrong answer.我就不信邪了,肯定是博主博客有错误,我就将博主的
//	交了一发,然而,博主的过了,我的没过.哎,一阵伤心,但心里也是再次
//	燃起了希望之火,还是可以搞得.然而我就仔细研究,对拍呗,自己造了
//	几个样例.发现下面这组:
//		4 2
//		A
//		C
//		T
//		GT
//	这组样例,答案应该是1,而我的答案是3.我仿佛一下子恍然大悟,发现
//	单个字符是病毒,不能走回根节点.明白了过后,一改,就AC了,虽然速度
//	有点慢,但是我发现自己对AC自动机的理解又有了一点小小的新的拓展
//	虽然作为菜鸟的我敢于怀疑是一件好事,但是自己的不对就是不对,不要
//	因为自己的自信就去刻意寻找别人的错误,认为别人是错误的.有着一颗
//	敢于承认错误,并且接受正确观念,并明悟的人,我觉得光明,就在前方!#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;typedef long long ll;const int MAX_NODE = 110;
const ll MOD = 100000;
const int MAX_N = 110;struct Matrix{ll mat[MAX_N][MAX_N];
}res;int n,m;struct Aho_Corasick{int ch[MAX_NODE][4];bool val[MAX_NODE];int f[MAX_NODE];//int last[MAX_NODE];int sz;void init(){memset(ch[0],-1,sizeof(ch[0]));val[0] = 0;sz = 1;f[0] = 0;//last[0] = 0;}int idx(char c){if (c == 'A')return 0;if (c == 'T')return 1;if (c == 'C')return 2;return 3;}void insert(char *s){int u = 0;int n = strlen(s);for (int i=0;i<n;i++){int c = idx(s[i]);if (ch[u][c]==-1){memset(ch[sz],-1,sizeof(ch[sz]));val[sz] = 0;ch[u][c] = sz++;}u = ch[u][c];}val[u] = true;}void getfail(){queue<int> que;f[0] = 0;for (int c = 0;c < 4;c++){int u = ch[0][c];if (u!=-1){que.push(u);f[u] = 0;//	last[u] = 0;}else{ch[0][c] = 0; //表示当此c单个字符不是病毒的时候,则可以走回根}}while(!que.empty()){int r = que.front();que.pop();if (val[f[r]]) // 当r的某个后缀为病毒的时候标记此rval[r] = true;for (int c = 0; c < 4;c++){int u = ch[r][c];if (u == -1){ch[r][c] = ch[f[r]][c]; //把不存在的边接上去continue;}que.push(u);int v = f[r];while(v && ch[v][c]==-1)v = f[v];f[u] = ch[v][c];//last[u] = val[f[u]] ? f[u] : last[f[u]];}}}void get_matrix(){memset(res.mat,0,sizeof(res.mat));for (int u=0;u<sz;u++){for (int c = 0;c < 4;c++){if (!val[u] && !val[ch[u][c]])res.mat[u][ch[u][c]]++;}}}}ac;Matrix Mulity(Matrix a,Matrix b){Matrix ans;for (int i=0;i < ac.sz;i++)for (int j=0;j < ac.sz;j++){ans.mat[i][j] = 0;for (int k=0;k < ac.sz ;k++)ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][k] * b.mat[k][j])%MOD;ans.mat[i][j] %= MOD;}return ans;
}Matrix Matrix_power(Matrix a,int b){Matrix ans;memset(ans.mat,0,sizeof(ans.mat));for (int i=0;i<ac.sz;i++)ans.mat[i][i] = 1;while(b){if (b & 1)	ans = Mulity(ans,a);a = Mulity(a,a);b >>=1;}return ans;
}void print(Matrix r){for (int i=0;i<ac.sz;i++){for (int j=0;j<ac.sz;j++)cout << r.mat[i][j] << " ";cout << endl;}
}void input(){ac.init();char s[20];for (int i=1;i<=m;i++){scanf("%s",s);ac.insert(s);}ac.getfail();ac.get_matrix();
//	print(res);res = Matrix_power(res,n);
//	cout << endl;
//	print(res);ll ans = 0;for (int i=0;i<ac.sz;i++){ans = (ans + res.mat[0][i])%MOD;}cout << ans%MOD << endl;
}int main(){//freopen("1.txt","r",stdin);while(scanf("%d%d",&m,&n)!=EOF){//	puts("-------");input();}return 0;
}

这篇关于poj 2778 AC自动机 + 矩阵快速幂的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/888594

相关文章

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

Win32下C++实现快速获取硬盘分区信息

《Win32下C++实现快速获取硬盘分区信息》这篇文章主要为大家详细介绍了Win32下C++如何实现快速获取硬盘分区信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实现代码CDiskDriveUtils.h#pragma once #include <wtypesbase

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

Python如何快速下载依赖

《Python如何快速下载依赖》本文介绍了四种在Python中快速下载依赖的方法,包括使用国内镜像源、开启pip并发下载功能、使用pipreqs批量下载项目依赖以及使用conda管理依赖,通过这些方法... 目录python快速下载依赖1. 使用国内镜像源临时使用镜像源永久配置镜像源2. 使用 pip 的并

SpringBoot快速接入OpenAI大模型的方法(JDK8)

《SpringBoot快速接入OpenAI大模型的方法(JDK8)》本文介绍了如何使用AI4J快速接入OpenAI大模型,并展示了如何实现流式与非流式的输出,以及对函数调用的使用,AI4J支持JDK8... 目录使用AI4J快速接入OpenAI大模型介绍AI4J-github快速使用创建SpringBoot

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景