[TJOI2018] 碱基序列
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=5337
[算法]
考虑构建后缀自动机
用fi , j表示前i个串 , 匹配到自动机上的j号节点方案数
在自动机上dp即可 , 详见代码
时间复杂度 : O(NK)
[代码]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 20010; const int ALPHA = 26; const int P = 1e9 + 7; #define rint register int int k; char s[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } struct Suffix_Automaton { int sz , last; int father[N] , child[N][ALPHA] , depth[N] , dp[2][N] , size[N]; vector< int > a[N]; Suffix_Automaton() { sz = 1; last = 1; } inline int new_node(int dep) { depth[++sz] = dep; father[sz] = 0; memset(child[sz] , 0 , sizeof(child[sz])); return sz; } inline void extend(int ch) { int np = new_node(depth[last] + 1); int p = last; for (; child[p][ch] == 0; p = father[p]) child[p][ch] = np; if (child[p][ch] == np) father[np] = 1; else { int q = child[p][ch]; if (depth[q] == depth[p] + 1) father[np] = q; else { int nq = new_node(depth[last] + 1); father[nq] = father[q]; father[np] = father[q] = nq; memcpy(child[nq] , child[q] , sizeof(child[nq])); for (; child[p][ch] == q; p = father[p]) child[p][ch] = nq; } } last = np; size[np] = 1; } inline void insert(char *s) { last = 1; for (rint i = 1; i <= strlen(s + 1); ++i) extend(s[i] - 'A'); } inline void dfs(int u , int par) { for (unsigned i = 0; i < a[u].size(); ++i) { if (a[u][i] != par) { dfs(a[u][i] , u); size[u] += size[a[u][i]]; } } } inline void update(int &x , int y) { x += y; while (x >= P) x -= P; } inline int find(int now , char *s) { for (rint i = 1; i <= strlen(s + 1); ++i) if (!child[now][s[i] - 'A']) return -1; else now = child[now][s[i] - 'A']; return now; } inline void calc() { for (rint i = 2; i <= sz; ++i) a[father[i]].push_back(i); dfs(1 , 0); dp[0][1] = 1; for (rint i = 1; i <= k; ++i) { int cnt; int now = i & 1 , pre = now ^ 1; read(cnt); for (rint j = 1; j <= sz; ++j) dp[now][j] = 0; for (rint j = 1; j <= cnt; ++j) { scanf("%s" , s + 1); for (rint frm = 1; frm <= sz; ++frm) { int to = find(frm , s); if (to != -1) update(dp[now][to] , dp[pre][frm]); } } } int ans = 0; for (rint i = 1; i <= sz; ++i) update(ans , 1LL * size[i] * dp[k & 1][i] % P); printf("%d\n" , ans); } } SAM; int main() { read(k); scanf("%s" , s + 1); SAM.insert(s); SAM.calc(); return 0; }