POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂
这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数。
题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的。
根据AC自动机的tire图,我们可以获得一个可达矩阵。
关于这题的tire图详解可以点击这里,往下面翻,这个博主的图对于tire图讲的非常详细。
知道了什么是tire图,理解了tire图后,后面的AC自动机的题目才能写。
AC自动机的灵魂应该就是tire图
然后问题就变成了,得到了一个可达矩阵后,如何求方案数呢?
这个n = 2000000000 这咋办呢?
给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值
这个是一个关于矩阵快速木的经典问题。
把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。
令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。
类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。
同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。
是不是就是一个裸的矩阵快速幂了。
通过AC自动机得到可达矩阵,然后通过矩阵快速幂求方案数。
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <set>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <ctime>
#include <vector> #define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt<<1
#define rtr rt<<1|1
#define bug printf("******\n")
#define mem(a, b) memset(a,b,sizeof(a))
#define name2str(x) #x
#define fuck(x) cout<<#x" = "<<x<<endl
#define sf(n) scanf("%d", &n)
#define sff(a, b) scanf("%d %d", &a, &b)
#define sfff(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define sffff(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define pf printf
#define FIN freopen("../date.txt","r",stdin)
#define gcd(a, b) __gcd(a,b)
#define lowbit(x) x&-x using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 3e3 + ;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = ; struct Matrix {
int mat[][], n; Matrix() {} Matrix(int _n) {
n = _n;
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
mat[i][j] = ;
} Matrix operator*(const Matrix &b) const {
Matrix ret = Matrix(n);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
for (int k = ; k < n; k++) {
int tmp = (long long) mat[i][k] * b.mat[k][j] % mod;
ret.mat[i][j] = (ret.mat[i][j] + tmp) % mod;
}
return ret;
}
}; Matrix pow_M(Matrix a, int b) {
Matrix ret = Matrix(a.n);
for (int i = ; i < ret.n; i++)
ret.mat[i][i] = ;
Matrix tmp = a;
while (b) {
if (b & )ret = ret * tmp;
tmp = tmp * tmp;
b >>= ;
}
return ret;
} struct Aho_Corasick {
int next[][], fail[], End[];
int root, cnt; int newnode() {
for (int i = ; i < ; i++) next[cnt][i] = -;
End[cnt++] = ;
return cnt - ;
} void init() {
cnt = ;
root = newnode();
} int get_num(char ch) {
if (ch == 'A') return ;
if (ch == 'T') return ;
if (ch == 'C') return ;
if (ch == 'G') return ;
} void insert(char buf[]) {
int len = strlen(buf);
int now = root;
for (int i = ; i < len; i++) {
if (next[now][get_num(buf[i])] == -) next[now][get_num(buf[i])] = newnode();
now = next[now][get_num(buf[i])];
}
End[now]++;
} void build() {
queue<int> Q;
fail[root] = root;
for (int i = ; i < ; i++)
if (next[root][i] == -) next[root][i] = root;
else {
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while (!Q.empty()) {
int now = Q.front();
Q.pop();
if (End[fail[now]]) End[now] = ;
for (int i = ; i < ; i++)
if (next[now][i] == -) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
} Matrix get_Matrix() {
Matrix ret = Matrix(cnt);
for (int i = ; i < cnt; ++i) {
for (int j = ; j < ; ++j) {
if (End[next[i][j]]) continue;
ret.mat[i][next[i][j]]++;
}
}
return ret;
} int query(char buf[]) {
int len = strlen(buf);
int now = root;
int res = ;
for (int i = ; i < len; i++) {
now = next[now][buf[i] - 'a'];
int temp = now;
while (temp != root) {
res += End[temp];
End[temp] = ;
temp = fail[temp];
}
}
return res;
} void debug() {
for (int i = ; i < cnt; i++) {
printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]);
for (int j = ; j < ; j++) printf("%2d", next[i][j]);
printf("]\n");
}
}
} ac; int n, m;
char str[maxn]; int main() {
// FIN;
sff(m, n);
ac.init();
for (int i = ; i < m; ++i) {
scanf("%s", str);
ac.insert(str);
}
ac.build();
Matrix mat = ac.get_Matrix();
mat = pow_M(mat, n);
LL ans = ;
for (int i = ; i < mat.n; ++i) {
ans = (ans + mat.mat[][i]) % mod;
}
printf("%lld\n", ans);
return ;
}
考研路茫茫――单词情结 HDU - 2243
这题和上题题意类似,做法一样。
上题是说长度为n的不包含m个模式串的方案数,这题求的是长度为1~n不包括m个模式串的方案数。
这题就在矩阵上面加上一列全为1的列,这个可以1保存了前面的方案书之和。
如果不理解的话,建议通过手算一下矩阵,去看看这个新加的一列有什么用。
这题是对2^64取模,所以直接用unsigned long long 自动溢出取模即可。
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <time.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map> #define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt<<1
#define rtr rt<<1|1
#define bug printf("******\n")
#define mem(a, b) memset(a,b,sizeof(a))
#define name2str(x) #x
#define fuck(x) cout<<#x" = "<<x<<endl
#define sf(n) scanf("%d", &n)
#define sff(a, b) scanf("%d %d", &a, &b)
#define sfff(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define sffff(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define pf printf
#define FIN freopen("../date.txt","r",stdin)
#define gcd(a, b) __gcd(a,b)
#define lowbit(x) x&-x
#define IO iOS::sync_with_stdio(false) using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 1e6 + ;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ; struct Matrix {
ULL mat[][], n; Matrix() {} Matrix(int _n) {
n = _n;
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
mat[i][j] = ;
} Matrix operator*(const Matrix &b) const {
Matrix ret = Matrix(n);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
for (int k = ; k < n; k++)
ret.mat[i][j] = ret.mat[i][j] + mat[i][k] * b.mat[k][j];
return ret;
}
}; Matrix pow_M(Matrix a, LL b) {
Matrix ret = Matrix(a.n);
for (int i = ; i < ret.n; i++)
ret.mat[i][i] = ;
Matrix tmp = a;
while (b) {
if (b & )ret = ret * tmp;
tmp = tmp * tmp;
b >>= ;
}
return ret;
} struct Aho_Corasick {
int next[][], fail[], End[];
int root, cnt; int newnode() {
for (int i = ; i < ; i++) next[cnt][i] = -;
End[cnt++] = ;
return cnt - ;
} void init() {
cnt = ;
root = newnode();
} void insert(char buf[]) {
int len = strlen(buf);
int now = root;
for (int i = ; i < len; i++) {
if (next[now][buf[i] - 'a'] == -) next[now][buf[i] - 'a'] = newnode();
now = next[now][buf[i] - 'a'];
}
End[now]++;
} void build() {
queue<int> Q;
fail[root] = root;
for (int i = ; i < ; i++)
if (next[root][i] == -) next[root][i] = root;
else {
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while (!Q.empty()) {
int now = Q.front();
Q.pop();
if (End[fail[now]]) End[now] = ;
for (int i = ; i < ; i++)
if (next[now][i] == -) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
} Matrix get_Matrix() {
Matrix ret = Matrix(cnt+);
for (int i = ; i < cnt; ++i) {
for (int j = ; j < ; ++j) {
if (!End[next[i][j]]) ret.mat[i][next[i][j]]++;
}
}
for (int i = ; i <= cnt; ++i) ret.mat[i][cnt] = ;
return ret;
} int query(char buf[]) {
int len = strlen(buf);
int now = root;
int res = ;
for (int i = ; i < len; i++) {
now = next[now][buf[i]];
int temp = now;
while (temp != root) {
res += End[temp];
End[temp] = ;
temp = fail[temp];
}
}
return res;
} void debug() {
for (int i = ; i < cnt; i++) {
printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]);
for (int j = ; j < ; j++) printf("%2d", next[i][j]);
printf("]\n");
}
}
} ac; char buf[];
LL n, m; int main() {
// FIN;
while (~scanf("%lld%lld", &n, &m)) {
ac.init();
for (int i = ; i < n; ++i) {
scanf("%s", buf);
ac.insert(buf);
}
ac.build();
Matrix mat = ac.get_Matrix();
mat = pow_M(mat, m);
ULL res = , ans = ;
for (int i = ; i < mat.n; ++i) res += mat.mat[][i];
Matrix a = Matrix();
a.mat[][] = , a.mat[][] = a.mat[][] = ;
a = pow_M(a, m);
ans = a.mat[][] + a.mat[][];
ans -= res;
printf("%llu\n", ans);
}
return ;
}
POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂的更多相关文章
- 考研路茫茫——单词情结 HDU - 2243 AC自动机 && 矩阵快速幂
背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...
- poj 2778 DNA Sequence ac自动机+矩阵快速幂
链接:http://poj.org/problem?id=2778 题意:给定不超过10串,每串长度不超过10的灾难基因:问在之后给定的长度不超过2e9的基因长度中不包含灾难基因的基因有多少中? DN ...
- 考研路茫茫――单词情结 HDU - 2243(ac自动机 + 矩阵快速幂)
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <23 ...
- HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)
背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...
- HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)
和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_ ...
- POJ 2778 DNA Sequence(AC自动机 + 矩阵快速幂)题解
题意:给出m个模式串,要求你构造长度为n(n <= 2000000000)的主串,主串不包含模式串,问这样的主串有几个 思路:因为要不包含模式串,显然又是ac自动机.因为n很大,所以用dp不太好 ...
- POJ 2778 DNA Sequence (ac自动机+矩阵快速幂)
DNA Sequence Description It's well known that DNA Sequence is a sequence only contains A, C, T and G ...
- DNA Sequence POJ - 2778 AC自动机 && 矩阵快速幂
It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to ...
随机推荐
- 自己的php框架
spl_autoload_register('imooc::load');当我们new的类不存在,将触发括号里的方法. is_file()判断文件是否存在.
- VS 2019企业版激活码
Visual Studio 2019 EnterpriseBF8Y8-GN2QH-T84XB-QVY3B-RC4DF
- C++11中的技术剖析(萃取技术)
从C++98开始萃取在泛型编程中用的特别多,最经典的莫过于STL.STL中的拷贝首先通过萃取技术识别是否是已知并且支持memcpy类型,如果是则直接通过内存拷贝提高效率,否则就通过类的重载=运算符,相 ...
- php上传(三)
关于一些上传插件的运用 JQuery上传插件Uploadify使用详解 http://www.cnblogs.com/oec2003/archive/2010/01/06/1640027.html
- 47 ubuntu指令整理学习
0 引言 在使用ubutnu时,积累了大量命令笔记.但是这些笔记比较零散,没有系统性,不便于查找和使用.通过系统性.分门别类地整理,希望可以增强对指令的记忆,提高工作效率,对ubuntu的使用更加地道 ...
- Android studio 安装apk时报错:INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries
flutter项目 华为手机真机安装报错,解决 办法 app build.gradle android {...}内添加一下代码 splits { abi { enable true reset() ...
- flutter 图片为空报错
imgpath != null ? Image.network(imgpath) : Container() 如果不判断imgpath 为空 network 内的url 为空就会报错
- CSDN首页> 云计算 孙玄:解析58同城典型技术架构及演变
转:http://www.csdn.net/article/2015-04-09/2824437 在UPYUN主办的“UPYUN Open Talk”第三期北京站上,58同城系统架构师孙玄详细介绍了5 ...
- ultis, BIT(x), BITCOUNT(x)
/* http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html */ #define BITCOUNT(x) (((BX_(x)+(BX_(x)> ...
- Cesium资料大全
前言 Cesium是一个用于显示三维地球和地图的开源js库.它可以用来显示海量三维模型数据.影像数据.地形高程数据.矢量数据等等.三维模型格式支持gltf.三维瓦片模型格式支持3d tiles.矢量数 ...