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

相关文章: