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自动机得到可达矩阵,然后通过矩阵快速幂求方案数。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <set>
  7 #include <iostream>
  8 #include <map>
  9 #include <stack>
 10 #include <string>
 11 #include <ctime>
 12 #include <vector>
 13
 14 #define  pi acos(-1.0)
 15 #define  eps 1e-9
 16 #define  fi first
 17 #define  se second
 18 #define  rtl   rt<<1
 19 #define  rtr   rt<<1|1
 20 #define  bug         printf("******\n")
 21 #define  mem(a, b)    memset(a,b,sizeof(a))
 22 #define  name2str(x) #x
 23 #define  fuck(x)     cout<<#x" = "<<x<<endl
 24 #define  sf(n)       scanf("%d", &n)
 25 #define  sff(a, b)    scanf("%d %d", &a, &b)
 26 #define  sfff(a, b, c) scanf("%d %d %d", &a, &b, &c)
 27 #define  sffff(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 28 #define  pf          printf
 29 #define  FIN               freopen("../date.txt","r",stdin)
 30 #define  gcd(a, b)    __gcd(a,b)
 31 #define  lowbit(x)   x&-x
 32
 33 using namespace std;
 34 typedef long long LL;
 35 typedef unsigned long long ULL;
 36 const int maxn = 3e3 + 7;
 37 const int maxm = 8e6 + 10;
 38 const int INF = 0x3f3f3f3f;
 39 const int mod = 100000;
 40
 41 struct Matrix {
 42     int mat[110][110], n;
 43
 44     Matrix() {}
 45
 46     Matrix(int _n) {
 47         n = _n;
 48         for (int i = 0; i < n; i++)
 49             for (int j = 0; j < n; j++)
 50                 mat[i][j] = 0;
 51     }
 52
 53     Matrix operator*(const Matrix &b) const {
 54         Matrix ret = Matrix(n);
 55         for (int i = 0; i < n; i++)
 56             for (int j = 0; j < n; j++)
 57                 for (int k = 0; k < n; k++) {
 58                     int tmp = (long long) mat[i][k] * b.mat[k][j] % mod;
 59                     ret.mat[i][j] = (ret.mat[i][j] + tmp) % mod;
 60                 }
 61         return ret;
 62     }
 63 };
 64
 65 Matrix pow_M(Matrix a, int b) {
 66     Matrix ret = Matrix(a.n);
 67     for (int i = 0; i < ret.n; i++)
 68         ret.mat[i][i] = 1;
 69     Matrix tmp = a;
 70     while (b) {
 71         if (b & 1)ret = ret * tmp;
 72         tmp = tmp * tmp;
 73         b >>= 1;
 74     }
 75     return ret;
 76 }
 77
 78 struct Aho_Corasick {
 79     int next[50010][4], fail[50010], End[50010];
 80     int root, cnt;
 81
 82     int newnode() {
 83         for (int i = 0; i < 4; i++) next[cnt][i] = -1;
 84         End[cnt++] = 0;
 85         return cnt - 1;
 86     }
 87
 88     void init() {
 89         cnt = 0;
 90         root = newnode();
 91     }
 92
 93     int get_num(char ch) {
 94         if (ch == ‘A‘) return 0;
 95         if (ch == ‘T‘) return 1;
 96         if (ch == ‘C‘) return 2;
 97         if (ch == ‘G‘) return 3;
 98     }
 99
100     void insert(char buf[]) {
101         int len = strlen(buf);
102         int now = root;
103         for (int i = 0; i < len; i++) {
104             if (next[now][get_num(buf[i])] == -1) next[now][get_num(buf[i])] = newnode();
105             now = next[now][get_num(buf[i])];
106         }
107         End[now]++;
108     }
109
110     void build() {
111         queue<int> Q;
112         fail[root] = root;
113         for (int i = 0; i < 4; i++)
114             if (next[root][i] == -1) next[root][i] = root;
115             else {
116                 fail[next[root][i]] = root;
117                 Q.push(next[root][i]);
118             }
119         while (!Q.empty()) {
120             int now = Q.front();
121             Q.pop();
122             if (End[fail[now]]) End[now] = 1;
123             for (int i = 0; i < 4; i++)
124                 if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
125                 else {
126                     fail[next[now][i]] = next[fail[now]][i];
127                     Q.push(next[now][i]);
128                 }
129         }
130     }
131
132     Matrix get_Matrix() {
133         Matrix ret = Matrix(cnt);
134         for (int i = 0; i < cnt; ++i) {
135             for (int j = 0; j < 4; ++j) {
136                 if (End[next[i][j]]) continue;
137                 ret.mat[i][next[i][j]]++;
138             }
139         }
140         return ret;
141     }
142
143     int query(char buf[]) {
144         int len = strlen(buf);
145         int now = root;
146         int res = 0;
147         for (int i = 0; i < len; i++) {
148             now = next[now][buf[i] - ‘a‘];
149             int temp = now;
150             while (temp != root) {
151                 res += End[temp];
152                 End[temp] = 0;
153                 temp = fail[temp];
154             }
155         }
156         return res;
157     }
158
159     void debug() {
160         for (int i = 0; i < cnt; i++) {
161             printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]);
162             for (int j = 0; j < 26; j++) printf("%2d", next[i][j]);
163             printf("]\n");
164         }
165     }
166 } ac;
167
168 int n, m;
169 char str[maxn];
170
171 int main() {
172   //  FIN;
173     sff(m, n);
174     ac.init();
175     for (int i = 0; i < m; ++i) {
176         scanf("%s", str);
177         ac.insert(str);
178     }
179     ac.build();
180     Matrix mat = ac.get_Matrix();
181     mat = pow_M(mat, n);
182     LL ans = 0;
183     for (int i = 0; i < mat.n; ++i) {
184         ans = (ans + mat.mat[0][i]) % mod;
185     }
186     printf("%lld\n", ans);
187     return 0;
188 }

考研路茫茫――单词情结 HDU - 2243

这题和上题题意类似,做法一样。

上题是说长度为n的不包含m个模式串的方案数,这题求的是长度为1~n不包括m个模式串的方案数。

这题就在矩阵上面加上一列全为1的列,这个可以1保存了前面的方案书之和。

如果不理解的话,建议通过手算一下矩阵,去看看这个新加的一列有什么用。

这题是对2^64取模,所以直接用unsigned long long 自动溢出取模即可。

  1 #include <set>
  2 #include <map>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <cstdio>
  7 #include <string>
  8 #include <vector>
  9 #include <time.h>
 10 #include <cstring>
 11 #include <iostream>
 12 #include <algorithm>
 13 #include <unordered_map>
 14
 15 #define  pi acos(-1.0)
 16 #define  eps 1e-9
 17 #define  fi first
 18 #define  se second
 19 #define  rtl   rt<<1
 20 #define  rtr   rt<<1|1
 21 #define  bug               printf("******\n")
 22 #define  mem(a, b)         memset(a,b,sizeof(a))
 23 #define  name2str(x)       #x
 24 #define  fuck(x)           cout<<#x" = "<<x<<endl
 25 #define  sf(n)             scanf("%d", &n)
 26 #define  sff(a, b)         scanf("%d %d", &a, &b)
 27 #define  sfff(a, b, c)     scanf("%d %d %d", &a, &b, &c)
 28 #define  sffff(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 29 #define  pf                printf
 30 #define  FIN               freopen("../date.txt","r",stdin)
 31 #define  gcd(a, b)         __gcd(a,b)
 32 #define  lowbit(x)         x&-x
 33 #define  IO                iOS::sync_with_stdio(false)
 34
 35
 36 using namespace std;
 37 typedef long long LL;
 38 typedef unsigned long long ULL;
 39 const int maxn = 1e6 + 7;
 40 const int maxm = 8e6 + 10;
 41 const int INF = 0x3f3f3f3f;
 42 const int mod = 1e9 + 7;
 43
 44 struct Matrix {
 45     ULL mat[110][110], n;
 46
 47     Matrix() {}
 48
 49     Matrix(int _n) {
 50         n = _n;
 51         for (int i = 0; i < n; i++)
 52             for (int j = 0; j < n; j++)
 53                 mat[i][j] = 0;
 54     }
 55
 56     Matrix operator*(const Matrix &b) const {
 57         Matrix ret = Matrix(n);
 58         for (int i = 0; i < n; i++)
 59             for (int j = 0; j < n; j++)
 60                 for (int k = 0; k < n; k++)
 61                     ret.mat[i][j] = ret.mat[i][j] + mat[i][k] * b.mat[k][j];
 62         return ret;
 63     }
 64 };
 65
 66 Matrix pow_M(Matrix a, LL b) {
 67     Matrix ret = Matrix(a.n);
 68     for (int i = 0; i < ret.n; i++)
 69         ret.mat[i][i] = 1;
 70     Matrix tmp = a;
 71     while (b) {
 72         if (b & 1)ret = ret * tmp;
 73         tmp = tmp * tmp;
 74         b >>= 1;
 75     }
 76     return ret;
 77 }
 78
 79 struct Aho_Corasick {
 80     int next[10010][26], fail[10010], End[10010];
 81     int root, cnt;
 82
 83     int newnode() {
 84         for (int i = 0; i < 26; i++) next[cnt][i] = -1;
 85         End[cnt++] = 0;
 86         return cnt - 1;
 87     }
 88
 89     void init() {
 90         cnt = 0;
 91         root = newnode();
 92     }
 93
 94     void insert(char buf[]) {
 95         int len = strlen(buf);
 96         int now = root;
 97         for (int i = 0; i < len; i++) {
 98             if (next[now][buf[i] - ‘a‘] == -1) next[now][buf[i] - ‘a‘] = newnode();
 99             now = next[now][buf[i] - ‘a‘];
100         }
101         End[now]++;
102     }
103
104     void build() {
105         queue<int> Q;
106         fail[root] = root;
107         for (int i = 0; i < 26; i++)
108             if (next[root][i] == -1) next[root][i] = root;
109             else {
110                 fail[next[root][i]] = root;
111                 Q.push(next[root][i]);
112             }
113         while (!Q.empty()) {
114             int now = Q.front();
115             Q.pop();
116             if (End[fail[now]]) End[now] = 1;
117             for (int i = 0; i < 26; i++)
118                 if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
119                 else {
120                     fail[next[now][i]] = next[fail[now]][i];
121                     Q.push(next[now][i]);
122                 }
123         }
124     }
125
126     Matrix get_Matrix() {
127         Matrix ret = Matrix(cnt+1);
128         for (int i = 0; i < cnt; ++i) {
129             for (int j = 0; j < 26; ++j) {
130                 if (!End[next[i][j]]) ret.mat[i][next[i][j]]++;
131             }
132         }
133         for (int i = 0; i <= cnt; ++i) ret.mat[i][cnt] = 1;
134         return ret;
135     }
136
137     int query(char buf[]) {
138         int len = strlen(buf);
139         int now = root;
140         int res = 0;
141         for (int i = 0; i < len; i++) {
142             now = next[now][buf[i]];
143             int temp = now;
144             while (temp != root) {
145                 res += End[temp];
146                 End[temp] = 0;
147                 temp = fail[temp];
148             }
149         }
150         return res;
151     }
152
153     void debug() {
154         for (int i = 0; i < cnt; i++) {
155             printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]);
156             for (int j = 0; j < 26; j++) printf("%2d", next[i][j]);
157             printf("]\n");
158         }
159     }
160 } ac;
161
162
163
164 char buf[1000010];
165 LL n, m;
166
167 int main() {
168    // FIN;
169     while (~scanf("%lld%lld", &n, &m)) {
170         ac.init();
171         for (int i = 0; i < n; ++i) {
172             scanf("%s", buf);
173             ac.insert(buf);
174         }
175         ac.build();
176         Matrix mat = ac.get_Matrix();
177         mat = pow_M(mat, m);
178         ULL res = 0, ans = 0;
179         for (int i = 0; i < mat.n; ++i) res += mat.mat[0][i];
180         Matrix a = Matrix(2);
181         a.mat[0][0] = 26, a.mat[1][0] = a.mat[1][1] = 1;
182         a = pow_M(a, m);
183         ans = a.mat[0][0] + a.mat[1][0];
184         ans -= res;
185         printf("%llu\n", ans);
186     }
187     return 0;
188 }

原文地址:https://www.cnblogs.com/qldabiaoge/p/11375935.html

时间: 2024-07-28 14:23:04

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂的相关文章

POJ POJ 2778 DNA Sequence AC自动机 + 矩阵快速幂

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就

hdu 2243 AC自动机 + 矩阵快速幂

// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 //

poj 2778 DNA Sequence(AC自动机+矩阵快速幂)

题目链接:poj 2778 DNA Sequence 题目大意:给定一些含有疾病的DNA序列,现在给定DNA长度,问有多少种不同的DNA序列是健康的. 解题思路:对DNA片段建立AC自动机,因为最多10个串,每个串最长为10,所以最多可能有100个节点,在长度为n时 以每个节点终止的健康字符串个数形成一个状态集,通过AC自动机形成的边可以推导出n+1的状态集,走到单词节点是 非法的,所以同样的我们可以先走到单词节点,但是从单词节点不向后转移.这样可以构造一个矩阵,剩下的就是矩阵 快速幂.注意的一

考研路茫茫――单词情结 HDU - 2243(ac自动机 + 矩阵快速幂)

考研路茫茫--单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6853    Accepted Submission(s): 2383 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了.一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如

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

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <231)的单词中至少含有一个词根的单词个数:结果mod 264. 基础:poj 2778DNA 序列求的是给定长度不含模式串的合法串的个数:串长度相当,都到了int上界了: 1.mod 264直接使用unsigned long long自然溢出即可:说的有些含蓄..并且也容易想到是直接使用内置类型,要不然高精度的

HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)

和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_sub(1)+solve(2)+...+solve_sub(n)).前者构造f[i]=f[i-1]*26+26然后矩阵快速幂即可(当然也可以分治的方法).后者即构造出dp矩阵p,然后计算(p^1+p^2+...+p^n),对其分治即可. 代码如下: 1 #include <stdio.h> 2 #

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

题目链接:DNA Sequence 解析:AC自动机 + 矩阵加速(快速幂). 这个时候AC自动机 的一种状态转移图的思路就很透彻了,AC自动机就是可以确定状态的转移. AC代码: #include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int MOD = 100000; struct Matrix{ int ma