【BZOJ1212】[HNOI2004]L語言
阿新 • • 發佈:2019-01-08
【BZOJ1212】[HNOI2004]L語言
題面
題解
其實可以不用AC自動機,但是最近在學就用了。。。
先把自動機建好,然後我們考慮怎麼做。
設$vis[x]$表示文字串中$1-x$是否可以被表示出來
然後暴跳$fail$
設我們當前跳到了點$p$,在字串的第$i$位
若有以$p$結尾的字串且$vis[i-dep[p]]$,就證明$vis[i]$可以被拼出來了
好像做完了?然而並沒有。
因為類似於$abcba$這樣的串也會被判成由$abc$和$cba$構成的
所以我們要開一個差分陣列看是否可以取到
體作可以看程式碼理解
程式碼
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int MAX_N = 2e6; const int MAX_M = 5000; struct AC_Auto { int c[MAX_M][26], fail[MAX_M], dep[MAX_M], cc[MAX_N], tot; bool vis[MAX_N], End[MAX_M]; AC_Auto() : tot(0) { } void insert(char *s) { int o = 0; for (int i = 1, l = strlen(s + 1); i <= l; i++) { int son = s[i] - 'a'; if (!c[o][son]) c[o][son] = ++tot; o = c[o][son]; dep[o] = i; } End[o] = 1; } void build() { static queue<int> que; for (int i = 0; i < 26; i++) if (c[0][i]) que.push(c[0][i]), fail[c[0][i]] = 0; while (!que.empty()) { int o = que.front(); que.pop(); for (int i = 0; i < 26; i++) if (c[o][i]) fail[c[o][i]] = c[fail[o]][i], que.push(c[o][i]); else c[o][i] = c[fail[o]][i]; } } int query(char *s) { memset(vis, 0, sizeof(vis)); memset(cc, 0, sizeof(cc)); vis[0] = 1; int l = strlen(s + 1); for (int i = 1, o = 0; i <= l; i++) { o = c[o][s[i] - 'a']; for (int x = o; x; x = fail[x]) if (End[x] && vis[i - dep[x]]) { vis[i] = 1; cc[i - dep[x] + 1]++; cc[i + 1]--; } } int res = 0; for (int i = 1, tot = 0; i <= l; i++) { tot += cc[i]; if (tot) ++res; else break; } return res; } } ac; int N, M; char s[MAX_N]; int main () { scanf("%d%d", &N, &M); for (int i = 1; i <= N; i++) scanf("%s", s + 1), ac.insert(s); ac.build(); while (M--) { scanf("%s", s + 1); printf("%d\n", ac.query(s)); } return 0; }