有一些病毒串,求长度为 L 的且不包含任意一个病毒串的字符串数量。
首先多串匹配,所以要建立 Trie 图(AC自动机)。而 L 很大,我们需要一个 O(log n) 的算法。考虑要得到一个长度为 n 的字符串,也就是在 Trie 图上走了 n 步。是不是似曾相识,很自然地就能想到矩阵乘法:首先根据 Trie图 求出 mat[ i ][ j ] ,表示从 i 节点到 j 节点走一步能到达的方案数(当然 i, j 都不能是病毒节点),然后计算这个矩阵的 n 次方,求和就能得到答案。
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX_N = 105;
const int mod = 100000;
struct Trie {
int ch[4], ed, fl;
} t[MAX_N];
int n, m, sz = 0;
char s[15];
int get_num(char c)
{
if (c == 'A') return 0;
if (c == 'C') return 1;
if (c == 'T') return 2;
if (c == 'G') return 3;
}
void insert()
{
int u = 0, l = strlen(s + 1);
for (int i = 1; i <= l; i ++) {
int c = get_num(s[i]);
if (!t[u].ch[c]) t[u].ch[c] = ++ sz;
u = t[u].ch[c];
}
t[u].ed = 1;
}
void init()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++)
scanf("%s", s + 1),
insert();
}
int q[100005];
void get_dna()
{
int hd = 0, tl = 0;
t[0].fl = 0;
for (int c = 0; c < 4; c ++)
if (t[0].ch[c]) {
t[t[0].ch[c]].fl = 0;
q[++ tl] = t[0].ch[c];
}
while (hd < tl) {
int r = q[++ hd];
for (int c = 0; c < 4; c ++) {
if (!t[r].ch[c]) {
t[r].ch[c] = t[t[r].fl].ch[c];
continue;
}
q[++ tl] = t[r].ch[c];
int u = t[r].ch[c], v = t[r].fl;
while (v && !t[v].ch[c]) v = t[v].fl;
t[u].fl = t[v].ch[c];
if (t[t[u].fl].ed) t[u].ed = 1;
}
}
}
struct Matrix {
long long mt[105][105];
}a;
Matrix operator*(Matrix a, Matrix b)
{
Matrix c;
for (int i = 0; i <= sz; i ++)
for (int j = 0; j <= sz; j ++) {
c.mt[i][j] = 0;
for (int k = 0; k <= sz; k ++)
c.mt[i][j] = (c.mt[i][j] + a.mt[i][k] * b.mt[k][j]) % mod;
}
return c;
}
Matrix operator^(Matrix a, int k)
{
Matrix ret;
for (int i = 0; i <= sz; i ++) {
for (int j = 0; j <= sz; j ++)
if (i == j) ret.mt[i][j] = 1;
else ret.mt[i][j] = 0;
}
while (k) {
if (k & 1) ret = ret * a;
a = a * a;
k >>= 1;
}
return ret;
}
void doit()
{
get_dna();
for (int i = 0; i <= sz; i ++)
for (int j = 0; j < 4; j ++)
if (!t[i].ed && !t[t[i].ch[j]].ed)
a.mt[i][t[i].ch[j]] ++;
a = a ^ m;
long long ans = 0;
for (int i = 0; i <= sz; i ++)
ans = (ans + a.mt[0][i]) % mod;
printf("%I64d\n", ans);
}
int main()
{
init();
doit();
return 0;
}