DNA Sequence POJ
阿新 • • 發佈:2019-02-17
這個題目利用了圖的思想,如果我們把ac自動機上面所有的點挑出來,建立一個矩陣M,表示i到j有幾條路徑可走,根據鄰接矩陣的性質,M的n次冪就表示從i到j走n步可以有多少條路。
如果我們結合ac自動機來看,那M的n第一行就表示長為n的,可行的字串數有多少了,就對應答案了
程式碼如下:
#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; }