这两题属于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 }