题目链接

题意

给定\(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;
}

最新文章

  1. JVM学习(4)——全面总结Java的GC算法和回收机制
  2. POJ 3292 Semi-prime H-numbers
  3. jquery 的 sort 函数
  4. PHP 5.4中的traits特性
  5. linux下奇怪的“重名”文件
  6. jquery 轮播图
  7. 跟SAP系统集成的Android应用
  8. ASP.NET自定义错误页面
  9. 编译时出现clock skew detected, your build may be incompeleted
  10. php 与redis 结合 使用predis
  11. log4j2日志模板
  12. mac Robotframework执行时报错Robot Framework installation not found.
  13. oracle表的基本操作
  14. Educational Codeforces Round 52 (Rated for Div. 2) -C
  15. windows Server 2008 R2 IE增强安全配置正在阻止来自下列网站的内容
  16. WIN7环境变量path误删(windows找不到文件‘%windir%\systempropertiesadvanced.exe’)的解决办法
  17. curd——5
  18. day02 大型互联网架构演变历程笔记 和nigix和keepalived
  19. N个数的最大公约数
  20. 蓝桥杯 地宫寻宝 DFS 动态规划

热门文章

  1. Linux 系统性能:观察、测试、调优
  2. systick运用
  3. java中equals和==区别
  4. sql中一个服务器建立另一个服务器的连接
  5. Go语言之反射(二)
  6. Spring Boot 开发系列一 开发踩坑
  7. loj2291 「THUSC 2016」补退选
  8. 云中Active Directory是如何工作的?
  9. python批量爬取文档
  10. Halcon18 windows 下载