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 ...
随机推荐
- Delphi 取整函数round、trunc、ceil和floor
Delphi 取整函数round.trunc.ceil和floor 1.Round(四舍六入五留双)功能说明:对一个实数进行四舍五入.(按照银行家算法)例:var i, j: Integer;begi ...
- 依赖背包变形——hdu4003
思维性比较强,代码挺简单的,dp[u][j]表示在u子树下安排j个机器人,让其不回u 注意转移时的初始值 /* dp[u][j]为在子树u有j个机器人不回来 */ #include<bits/s ...
- (转)The connection to adb is down, and a severe error has occured. .
转:http://blog.csdn.net/yu413854285/article/details/7559333 启动android模拟器时.有时会报The connection to adb i ...
- 8、collection
collection 可以理解为一个容器 组织业务逻辑 导入导出 监控或者mock server 实例: 1.新建一个collection,命名为v2ex 2.保存1个请求到v2ex 3.选中v2ex ...
- 常用的一些 linux 指令
1. mv linux下重命名文件或文件夹使用mv既可实现. 1.1 重命名 a.将一个名为abc.txt的文件重命名为1234.txt #mv abc.txt .txt b. 将目录A重命名为B ( ...
- UVA 12676 Inverting Huffman
题目链接:https://vjudge.net/problem/UVA-12676 题目大意 一串文本中包含 N 个不同字母,经过哈夫曼编码后,得到这 N 个字母的相应编码长度,求文本的最短可能长度. ...
- ubuntu 删除 mysql (转)
1 sudo apt-get autoremove --purge mysql-server-5.0 2 sudo apt-get remove mysql-server 3 sudo apt-get ...
- python学习6—数据类型之集合与字符串格式化
python学习6—数据类型之集合与字符串格式化 1. 使用id()可以查看一个变量的内存地址: name = 'alex' id(name) 2. 进制转换 十进制转换为二进制等: a = 10 # ...
- [JSOI2019]精准预测
题目 这么明显的限制条件显然是\(\text{2-sat}\) 考虑按照时间拆点,\((0/1,x,t)\)表示\(x\)个人在时间\(t\)是生/死 有一些显然的连边 \[(0,x,t+1)-> ...
- 5个Sublime Text 的插件推荐
Sublime Text 是一个代码编辑器(Sublime Text 2是收费软件,但可以无限期试用),也是HTML和散文先进的文本编辑器.Sublime Text是由程序员Jon Skinner于2 ...