poj2778
AC自动机+矩阵乘法
套路$dp$,也就是从$root$开始走n步不经过危险节点
这不就是经典的倍增$floyd$吗,trie图是有向图
AC自动机真是个奇怪的东西,不能识别的子串都属于根节点
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const int N = 105, P = 1e5; int n, m; int mp[N]; char s[N]; namespace ac { int root, cnt; struct node { int ch[4]; int fail, f; } t[N]; void insert(char *s) { int len = strlen(s), now = root; for(int i = 0; i < len; ++i) { int &v = t[now].ch[mp[s[i]]]; if(!v) { v = ++cnt; } now = v; } t[now].f = 1; } void construct_fail() { queue<int> q; for(int i = 0; i < 4; ++i) { if(!t[root].ch[i]) { // t[root].ch[i] = ++cnt; } if(t[root].ch[i]) { q.push(t[root].ch[i]); } } while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < 4; ++i) { int &v = t[u].ch[i]; if(!v) { v = t[t[u].fail].ch[i]; } else { t[v].fail = t[t[u].fail].ch[i]; t[v].f |= t[t[v].fail].f; q.push(v); } } } } } using namespace ac; struct matrix { ll a[N][N]; matrix() { memset(a, 0, sizeof(a)); } void set() { for(int i = 0; i <= cnt; ++i) { a[i][i] = 1; } } matrix friend operator * (const matrix &a, const matrix &b) { matrix ret; for(int k = 0; k <= cnt; ++k) { for(int i = 0; i <= cnt; ++i) { for(int j = 0; j <= cnt; ++j) { ret.a[i][j] = (ret.a[i][j] + a.a[i][k] * b.a[k][j] % P) % P; } } } return ret; } } M, a; int main() { mp['A'] = 0; mp['G'] = 1; mp['C'] = 2; mp['T'] = 3; scanf("%d%d", &m, &n); for(int i = 1; i <= m; ++i) { scanf("%s", s); insert(s); } construct_fail(); for(int i = 0; i <= cnt; ++i) { for(int j = 0; j < 4; ++j) { int v = t[i].ch[j]; if(t[v].f) { continue; } ++a.a[i][v]; } } M.set(); for(int i = n; i; i >>= 1, a = a * a) { if(i & 1) { M = M * a; } } ll ans = 0; for(int i = 0; i <= cnt; ++i) { ans = (ans + M.a[0][i]) % P; } printf("%lld\n", ans); return 0; }