HDU 5880 Family View (2016 青岛网络赛 C题,AC自动机)
题目链接 2016 青岛网络赛 Problem C
题意 给出一些敏感词,和一篇文章。现在要屏蔽这篇文章中所有出现过的敏感词,屏蔽掉的用$'*'$表示。
建立$AC$自动机,查询的时候沿着$fail$指针往下走,当匹配成功的时候更新$f[i]$
$f[i]$表示要屏蔽以第$i$个字母结尾的长度为$f[i]$的字符串。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define fi first #define se second typedef long long LL; const int N = 1e6 + 10; int T, n; int f[N]; char buf[N]; struct Trie{ int nxt[N][26], fail[N], end[N], len[N]; int root, tot; int newnode(){ rep(i, 0, 25) nxt[tot][i] = -1; len[tot] = end[tot] = 0; tot++; return tot - 1; } void init(){ tot = 0; root = newnode(); } void ins(char buf[]){ int l = strlen(buf); int now = root; rep(i, 0, l - 1){ if (nxt[now][buf[i] - 'a'] == -1) nxt[now][buf[i] - 'a'] = newnode(); now = nxt[now][buf[i] - 'a']; } end[now]++; len[now] = strlen(buf); } void build(){ queue <int> q; fail[root] = root; rep(i, 0, 25){ if (~nxt[root][i]){ fail[nxt[root][i]] = root; q.push(nxt[root][i]); } else nxt[root][i] = root; } while (!q.empty()){ int now = q.front(); q.pop(); rep(i, 0, 25){ if (~nxt[now][i]){ fail[nxt[now][i]] = nxt[fail[now]][i]; q.push(nxt[now][i]); } else nxt[now][i] = nxt[fail[now]][i]; } } } void query(char buf[]){ int l = strlen(buf); int now = root; int res = 0; rep(i, 0, l - 1){ int sign; if (buf[i] >= 'A' && buf[i] <= 'Z') sign = buf[i] - 'A'; else if (buf[i] >= 'a' && buf[i] <= 'z') sign = buf[i] - 'a'; else{ now = root; continue; } now = nxt[now][sign]; int temp = now; while (temp != root){ f[i] = max(f[i], len[temp]); temp = fail[temp]; } } } } ac; int leng, num; int main(){ scanf("%d",&T); while (T--){ scanf("%d",&n); ac.init(); rep(i, 1, n){ scanf("%s", buf); ac.ins(buf); } ac.build(); getchar(); gets(buf); memset(f, 0, sizeof f); ac.query(buf); leng = strlen(buf); num = 0; dec(i, leng - 1, 0){ num = max(num, f[i]); if (num == 0) continue; else buf[i] = '*', num--; } puts(buf); } return 0; }