pdf题面:传送门
题目大意:给定一些单词和一个句子,问有多少个单词在句子中出现过,如果一个但单词包含另一个单词,并且两个单词都出现过,那么只算最外层的单词(包含另一个单词的单词).
分析:这道题如果没有第二个条件的话就和hdu2222是一模一样的题.但是没关系,可以先用hdu2222的方法找出所有出现过的单词,然后每个单词将它的子串给标记.如何找一个串的子串呢?如果一个字符串s[1......n],它的子串必定在s[1......r]和s[l......n]中,也就是在前缀和后缀中,在trie里,找前缀可以利用父亲节点.找后缀可以利用AC自动机的fail指针,这样递归地标记一下就可以了.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 200010,maxm = 5120010; char s[maxm],ss[maxm]; int T,n,cnt,tot = 1,ans; bool vis[maxn],tag[maxn],vis2[maxn]; void init() { n = cnt = ans = 0; memset(vis,false,sizeof(vis)); memset(vis2,false,sizeof(vis2)); memset(tag,false,sizeof(tag)); } struct node { int tr[30],fail,id,fa; void clear() { memset(tr,0,sizeof(tr)); fail = id = fa = 0; } } e[maxn]; void insert(int x) { int u = 1; for (int i = 1; i <= cnt; i++) { int ch = ss[i] - 'A'; if (!e[u].tr[ch]) { e[u].tr[ch] = ++tot; e[tot].clear(); } int temp = u; u = e[u].tr[ch]; e[u].fa = temp; } e[u].id = x; } void build() { queue <int> q; for (int i = 0; i < 26; i++) e[0].tr[i] = 1; q.push(1); while (!q.empty()) { int u = q.front(); q.pop(); int fail = e[u].fail; for (int i = 0; i < 26; i++) { int y = e[u].tr[i]; if (y) { e[y].fail = e[fail].tr[i]; q.push(y); } else e[u].tr[i] = e[fail].tr[i]; } } } void dfs(int x) { if (tag[x]) return; tag[x] = 1; vis[x] = 0; if (e[x].fail) dfs(e[x].fail); if (e[x].fa) dfs(e[x].fa); } bool ischar(char p) { return p >= 'A' && p <= 'Z'; } void getchange() { int len = strlen(s + 1); cnt = 0; for (int i = 1; i <= len; i++) { if (ischar(s[i])) ss[++cnt] = s[i]; else { i++; int res = 0; while (s[i] >= '0' && s[i] <= '9') { res = res * 10 + s[i] - '0'; i++; } char cc = s[i++]; while (res) { ss[++cnt] = cc; res--; } } } } int main() { scanf("%d",&T); while (T--) { init(); e[tot = 1].clear(); scanf("%d",&n); for (int i = 1; i <= n; i++) { scanf("%s",s + 1); getchange(); insert(i); } build(); scanf("%s",s + 1); getchange(); int u = 1; for (int i = 1; i <= cnt; i++) { int ch = ss[i] - 'A'; while (u && !e[u].tr[ch]) u = e[u].fail; u = e[u].tr[ch]; int t = u; while (t && !vis2[t]) { vis2[t] = 1; if (e[t].id) vis[t] = 1; t = e[t].fail; } } for (int i = 1; i <= tot; i++) if (!tag[i] && vis[i]) { dfs(e[i].fail); dfs(e[i].fa); } for (int i = 1; i <= tot; i++) if (vis[i]) ans++; printf("%d ",ans); } return 0; }