版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/84449776
【思路要点】
- 考虑从两端向中间 。
- 对于此类匹配问题,考虑建立 自动机来描述状态。
- 对 集合建立 自动机 ,对 集合中所有串的反串建立 自动机 。
- 记 表示决策了最终字符串开头和结尾的 个字符,在 上的匹配到的节点为 ,在 上的匹配到的节点为 ,成功匹配的次数为 ,显然成功匹配的次数超过 的状态是没有意义的。
- 完成决策后,对成功匹配次数为 的状态检验 和 对应的字符串拼接后是否包含了关键串,忽略包含了关键串的状态,将其余的方案数计入答案。
- 其时间复杂度看似是 的,但注意到 和 对应的字符串存在一个前后缀的关系,因此如果我们忽略无法达到的状态,时间复杂度实际上为 ,并且常数很小。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2005; const int MAXM = MAXN * MAXN; const int P = 1e9 + 7; typedef long long ll; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct ACAutoMaton { struct Node { int child[2]; int fail, type, father; bool key; } a[MAXN]; int root, size; void init() { root = 0; size = 0; } void insert(char *s, bool flg) { int len = strlen(s + 1); if (flg) { int now = root; for (int i = len; i >= 1; i--) { int tmp = s[i] - '0'; if (a[now].child[tmp] == 0) { a[now].child[tmp] = ++size; a[size].father = now; } now = a[now].child[tmp]; a[now].type = tmp; } a[now].key = true; } else { int now = root; for (int i = 1; i <= len; i++) { int tmp = s[i] - '0'; if (a[now].child[tmp] == 0) { a[now].child[tmp] = ++size; a[size].father = now; } now = a[now].child[tmp]; a[now].type = tmp; } a[now].key = true; } } void build() { static int q[MAXN]; int l = 0, r = -1; for (int i = 0; i <= 1; i++) if (a[root].child[i]) { q[++r] = a[root].child[i]; a[q[r]].fail = root; } else a[root].child[i] = root; while (l <= r) { int tmp = q[l++]; for (int i = 0; i <= 1; i++) if (a[tmp].child[i] == 0) a[tmp].child[i] = a[a[tmp].fail].child[i]; else { q[++r] = a[tmp].child[i]; a[q[r]].fail = a[a[tmp].fail].child[i]; } } for (int i = 0; i <= r; i++) { int tmp = q[i]; a[tmp].key |= a[a[tmp].fail].key; } } pair <int, bool> step(int x, int y) { x = a[x].child[y]; if (a[x].key) return make_pair(root, true); else return make_pair(x, false); } } ACAM[2]; int n, m; char s[MAXN][35]; int num[MAXN][MAXN]; int dp[2][MAXM][2]; int timer, x[MAXM], y[MAXM]; int func(int posx, int posy) { if (num[posx][posy]) return num[posx][posy]; num[posx][posy] = ++timer; x[timer] = posx, y[timer] = posy; return timer; } void update(int &x, int y) { x += y; if (x >= P) x -= P; } int main() { read(n), read(m); ACAM[0].init(); ACAM[1].init(); for (int i = 1; i <= m; i++) { scanf("\n%s", s[i] + 1); ACAM[0].insert(s[i], false); ACAM[1].insert(s[i], true); } ACAM[0].build(); ACAM[1].build(); dp[0][func(0, 0)][0] = 1; for (int i = 1, from = 0, now = 1; i <= n / 2; i++, swap(from, now)) { for (int j = 1; j <= timer; j++) for (int k = 0; k <= 1; k++) dp[now][j][k] = 0; int ttimer = timer; for (int j = 1; j <= ttimer; j++) for (int k = 0; k <= 1; k++) { int px = x[j], py = y[j]; pair <int, bool> tx, ty; tx = ACAM[0].step(px, 0); ty = ACAM[1].step(py, 0); if (k + tx.second + ty.second <= 1) update(dp[now][func(tx.first, ty.first)][k + tx.second + ty.second], dp[from][j][k]); tx = ACAM[0].step(px, 1); ty = ACAM[1].step(py, 1); if (k + tx.second + ty.second <= 1) update(dp[now][func(tx.first, ty.first)][k + tx.second + ty.second], dp[from][j][k]); } } int now = (n / 2) & 1, ans = 0; if (n & 1) { for (int i = 1; i <= timer; i++) { update(ans, 2 * dp[now][i][0] % P); bool flg = true; int px = x[i], py = y[i]; pair <int, bool> tmp = ACAM[0].step(px, 0); if (!tmp.second) { px = tmp.first; while (py != 0) { pair <int, bool> tmp = ACAM[0].step(px, ACAM[1].a[py].type); if (tmp.second) { flg = false; break; } px = tmp.first; py = ACAM[1].a[py].father; } if (flg) update(ans, dp[now][i][1]); } flg = true; px = x[i], py = y[i]; tmp = ACAM[0].step(px, 1); if (!tmp.second) { px = tmp.first; while (py != 0) { pair <int, bool> tmp = ACAM[0].step(px, ACAM[1].a[py].type); if (tmp.second) { flg = false; break; } px = tmp.first; py = ACAM[1].a[py].father; } if (flg) update(ans, dp[now][i][1]); } } } else { for (int i = 1; i <= timer; i++) { update(ans, dp[now][i][0]); bool flg = true; int px = x[i], py = y[i]; while (py != 0) { pair <int, bool> tmp = ACAM[0].step(px, ACAM[1].a[py].type); if (tmp.second) { flg = false; break; } px = tmp.first; py = ACAM[1].a[py].father; } if (flg) update(ans, dp[now][i][1]); } } writeln(ans); return 0; }