题目链接

题意

给定\(m\)个字符串,问长度为\(n\)的字符串中有多少个不包含那\(m\)个字符串。

(字符集为\(A,T,C,G\),\(m\leq 10\),长度\(\leq 10\),\(n\leq 2e9\))

思路

状态转移——矩阵

构造一个矩阵\(m[\ ][\ ]\),\(m[i][j]\)代表有多少种方式可以走一步从第\(i\)个节点到第\(j\)个节点

则\(m^n[i][j]\)即代表有多少种方式可以走\(n\)步从第\(i\)个节点到第\(j\)个节点

于是答案呼之欲出——\(\sum_{i=0}^{cnt}m^n[0][i]\),即从根节点走到其他所有节点的方式数总和。

状态——AC自动机

且慢,上面说的节点是什么?

——是\(AC\)自动机上的状态节点(AC自动机本质上是状态机)。

那么走一步又是怎么体现的?

——从\(x\)走到\(son[x][i]\)即为走一步。

不能包含的状态又是怎么处理呢?

——将所有能够通过fail指针走到某个单词结尾状态的节点全都排除,这一点由后缀关系易见。

Code

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
#define SIZE 4
#define maxn 110
using namespace std;
typedef long long LL;
char s[12];
int son[maxn][4], fail[maxn], flag[maxn], mp[maxn], mp2[maxn], tot, mat[maxn][maxn];
void add(char* s, int len) {
int p = 0;
for (int i = 0; i < len; ++i) {
if (son[p][mp[s[i]]] == -1) {
flag[++tot] = 0;
for (int j = 0; j < SIZE; ++j) son[tot][j] = -1;
son[p][mp[s[i]]] = tot;
}
p = son[p][mp[s[i]]];
}
flag[p] = 1;
}
void build() {
queue<int> que;
fail[0] = 0;
for (int i = 0; i < SIZE; ++i) {
if (son[0][i] == -1) son[0][i] = 0;
else {
fail[son[0][i]] = 0;
que.push(son[0][i]);
}
++mat[0][son[0][i]];
}
while (!que.empty()) {
int x = que.front(); que.pop();
for (int i = 0; i < SIZE; ++i) {
if (son[x][i] == -1) son[x][i] = son[fail[x]][i];
else {
fail[son[x][i]] = son[fail[x]][i];
flag[son[x][i]] |= flag[fail[son[x][i]]];
que.push(son[x][i]);
}
++mat[x][son[x][i]];
}
}
}
void init() {
mp['A'] = 0, mp['T'] = 1, mp['C'] = 2, mp['G'] = 3;
flag[tot = 0] = 0;
for (int i = 0; i < SIZE; ++i) son[0][i] = -1;
}
int cnt;
const LL mod = 100000;
typedef struct {
LL mat[maxn][maxn];
void init(LL x){
memset(mat, 0, sizeof(mat));
for(int i=0; i<cnt; i++) mat[i][i] = x;
}
} Matrix;
Matrix m0;
LL addl(LL a, LL b) { return (a + b + mod) % mod; }
LL mull(LL a, LL b) { return a * b % mod; }
Matrix mulm(const Matrix& a, const Matrix& b) {
Matrix temp;
temp.init(0);
for (int i = 0; i < cnt; ++i) {
for (int j = 0; j < cnt; ++j) {
for (int k = 0; k < cnt; ++k) temp.mat[i][j] = addl(temp.mat[i][j], mull(a.mat[i][k], b.mat[k][j]));
}
}
return temp;
}
Matrix poww(LL n) {
Matrix a = m0, ret;
ret.init(1);
while (n) {
if (n & 1) ret = mulm(ret, a);
a = mulm(a, a);
n >>= 1;
}
return ret;
}
int main() {
int m; LL n;
scanf("%d%lld", &m, &n);
init();
for (int i = 0; i < m; ++i) {
scanf("%s", &s);
add(s, strlen(s));
}
build();
cnt=0;
for (int i = 0; i <= tot; ++i) if (!flag[i]) mp2[cnt++] = i;
for (int i = 0; i < cnt; ++i) {
for (int j = 0; j < cnt; ++j) {
m0.mat[i][j] = mat[mp2[i]][mp2[j]];
}
} Matrix fnl = poww(n);
LL ans=0;
for (int i = 0; i < cnt; ++i) ans = addl(ans, fnl.mat[0][i]);
printf("%lld\n", ans);
return 0;
}

poj 2778 DNA Sequence 状态及状态转移 AC自动机 矩阵快速幂的更多相关文章

  1. 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 ...

  2. 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 ...

  3. POJ2778 DNA Sequence(AC自动机+矩阵快速幂)

    题目给m个病毒串,问不包含病毒串的长度n的DNA片段有几个. 感觉这题好神,看了好久的题解. 所有病毒串构造一个AC自动机,这个AC自动机可以看作一张有向图,图上的每个顶点就是Trie树上的结点,每个 ...

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

    题目链接:https://vjudge.net/problem/POJ-2778 题意:输入n和m表示n个病毒,和一个长为m的字符串,里面只可以有'A','C','G','T' 这四个字符,现在问这个 ...

  5. POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

    这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的t ...

  6. poj2778DNA Sequence (AC自动机+矩阵快速幂)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud DNA Sequence Time Limit: 1000MS   Memory ...

  7. POJ 2778 DNA Sequence(AC自动机+矩阵快速幂)

    题目链接:http://poj.org/problem?id=2778 题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) ...

  8. poj 2778 DNA Sequence ac自动机+矩阵快速幂

    链接:http://poj.org/problem?id=2778 题意:给定不超过10串,每串长度不超过10的灾难基因:问在之后给定的长度不超过2e9的基因长度中不包含灾难基因的基因有多少中? DN ...

  9. poj2778 DNA Sequence(AC自动机+矩阵快速幂)

    Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's ve ...

随机推荐

  1. 【PHP】常用的PHP正则表达式收集整理

    匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达式就好办了 匹配双字节字符(包括汉字在内):[^\x00-\xff]评注:可以用来计算字符串的长度 ...

  2. Gearman任务分配

    Gearman 实现多数据库数据同步 测试环境:windows(mysql)+ 虚拟机(ubuntu + mysql)+ PHP 1:gearman 的官方文档可以了解gearman,在ubuntu中 ...

  3. Why I get “No connection associated with this command”?

  4. LED室内定位算法:RSS,TOA,AOA,TDOA(转载)

    转载自:https://blog.csdn.net/baidu_38197452/article/details/77115935 基于LED的室内定位算法大致可以分为四类: 1. 几何测量法 这种方 ...

  5. [BSOJ2684]锯木厂选址(斜率优化)

    Description 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂.木材只能按照一个方向运输:朝山下运.山脚下有一个锯木厂 ...

  6. unity安装记录

    官网直接下载(http://unity3d.com/cn/) 下载完后,会要求输入账号密码.我是先在官网进行一个账号注册,然后登陆即可. 首先会要你输入一个已有的邮箱,进行认证.进入自己邮箱,点击链接 ...

  7. 《鸟哥的Linux私房菜》学习笔记(8)——bash脚本编程之变量

    一.变量命名                                                             1.只能包含字母.数字和下划线,并且不能以数字开头,    2.不 ...

  8. 68、TSPL指令集(标签打印机)

    0.开发者pdf.sdk等资料详见: http://download.csdn.net/detail/kunyashaw/9376694 1.测试代码 包含文字打印.条形码打印.二维码打印 packa ...

  9. 【Rotate Image】cpp

    题目: You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwis ...

  10. CentOS安装jdk和tomcat

    1.查看是否已经安装 java -version 2.卸载自带的openjdk dnf remove java-1.7.0-openjdk 3.下载jdk安装包 wget -c http://111. ...