题目链接https://cn.vjudge.net/problem/POJ-2778
这个题目利用了图的思想,如果我们把ac自动机上面所有的点挑出来,建立一个矩阵M,表示i到j有几条路径可走,根据邻接矩阵的性质,M的n次幂就表示从i到j走n步可以有多少条路。
如果我们结合ac自动机来看,那M的n第一行就表示长为n的,可行的字符串数有多少了,就对应答案了
参考博客:https://blog.csdn.net/morgan_xww/article/details/7834801
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
struct AC_Automata {
#define Nn 102
#define M 4
int ch[Nn][M], val[Nn], f[Nn], last[Nn], sz;
void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
int idx(char c) {
if (c == 'A') return 0;
if (c == 'C') return 1;
if (c == 'T') return 2;
return 3;
}
void insert(char s[], int v) {
int u = 0;
for (int i=0; s[i]; i++) {
int c = idx(s[i]);
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = 1; ///标记当前节点是病毒串
}
void build() {
queue<int> q;
f[0] = 0;
for (int c=0; c<M; c++) {
int u = ch[0][c];
if (u) { f[u] = last[u] = 0; q.push(u); }
}
while (!q.empty()) {
int r = q.front(); q.pop();
for (int c=0; c<M; c++) {
int u = ch[r][c];
if (!u) {
ch[r][c] = ch[f[r]][c];
// val[r] = val[r] || val[f[r]]; ///如果失配边指向的结点是病毒,那么当前串的后缀也是病毒串
continue;
}
q.push(u);
f[u] = ch[f[r]][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
} ac;
#define Mod 100000ll
#define N 200
ll a[N][N];
int n;
//c = a*b
void Multi(ll a[][N], ll b[][N], ll c[][N]) {
for (int i=0; i<n; i++)
for (int j=0; j<n; j++) {
c[i][j] = 0;
for (int k=0; k<n; k++)
c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % Mod;
}
}
//d = s
void copy(ll d[][N], ll s[][N]) {
for (int i=0; i<n; i++) for (int j=0; j<n; j++)
d[i][j] = s[i][j];
}
//a = a^b % Mod
void PowerMod(ll a[][N], ll b) {
ll t[N][N], ret[N][N];
for (int i=0; i<n; i++) ret[i][i] = 1;
while (b) {
if (b & 1) { Multi(ret, a, t); copy(ret, t); }
Multi(a, a, t); copy(a, t);
b >>= 1;
}
copy(a, ret);
}
void init() {
n = ac.sz;
int u;
memset(a, 0, sizeof(a));
for (int i=0; i<n; i++) if (!ac.val[i] && !ac.last[i]) {
for (int j=0; j<4; j++) {
u = ac.ch[i][j];
if (!ac.val[u] && !ac.last[u]) a[i][u]++;
}
}
}
int main() {
char s[12];
int m;
ll b;
while (scanf("%d %lld", &m, &b) == 2) {
ac.clear();
for (int i=1; i<=m; i++) {
scanf(" %s", s); ac.insert(s, i);
}
ac.build();
init();
PowerMod(a, b);
ll sum = 0;
for (int i=0; i<n; i++) sum = (sum + a[0][i]) % Mod;
cout << sum << endl;
}
return 0;
}