【省內訓練2018-11-23】Palindrome
阿新 • • 發佈:2018-11-27
【思路要點】
- 考慮從兩端向中間 。
- 對於此類匹配問題,考慮建立 自動機來描述狀態。
- 對 集合建立 自動機 ,對 集合中所有串的反串建立 自動機 。
- 記 表示決策了最終字串開頭和結尾的 個字元,在 上的匹配到的節點為 ,在 上的匹配到的節點為 ,成功匹配的次數為 ,顯然成功匹配的次數超過 的狀態是沒有意義的。
- 完成決策後,對成功匹配次數為 的狀態檢驗 和 對應的字串拼接後是否包含了關鍵串,忽略包含了關鍵串的狀態,將其餘的方案數計入答案。
- 其時間複雜度看似是 的,但注意到 和 對應的字串存在一個前後綴的關係,因此如果我們忽略無法達到的狀態,時間複雜度實際上為 ,並且常數很小。
【程式碼】
#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; }