ac自动机。先把单词按照题意排序,把询问串建成trie树,然后按照单词顺序进行查询,注意好结果保存,询问串可能会有重复。
#include <cstdio> #include <cstring> #include <string> #include <vector> #include <iostream> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; const int N = 1000000+10; const int M = 10001 * 50; const int ch = 26; int sw[128]; int trie[M][ch+1], top, n, q[M], bg, ed, fail[M]; bool vis[M]; char str[N]; vector<int>ans[N], tim[N]; struct acstr { int id; string s; void get(int i){ id=i; gets(str); s=str;} bool operator < (const acstr& a)const{ if (s.length()==a.s.length()){ if (s == a.s)return id < a.id; return s < a.s; } return s.length() < a.s.length(); } }buf[20010]; void init(){ top = 1; clr(trie[0], 0); for (char i='a', j=0; i<='z'; i++, j++) sw[i] = j; } void ins(char *s, int rank){ int rt, nxt; for (rt=0; *s; rt=nxt, s++){ nxt = trie[rt][sw[*s]]; if (nxt == 0){ clr(trie[top], 0); trie[rt][sw[*s]]=nxt=top++; } } tim[rt].push_back(rank); // 保存该点id,不能直接覆盖,可能会有重复 } void makefail(){ int u, v; fail[0] = bg = ed = 0; for (int i=0; i<ch; i++) if (q[ed] = trie[0][i]) fail[q[ed++]] = 0; while (bg < ed){ u = q[bg++]; for (int i=0; i<ch; i++){ if (v = trie[u][i]) q[ed++]=v, fail[v]=trie[fail[u]][i]; else trie[u][i] = trie[fail[u]][i]; } } } void ac(const char *s, int id){ clr(vis, 0); for (int i=0; *s; s++){ i=trie[i][sw[*s]]; for (int j=i,v; j; j=fail[j]){ for (int k=0; k<tim[j].size(); k++){ v=tim[j][k]; if(vis[v])continue; vis[v] = true; if (ans[v].size()<10)ans[v].push_back(id); } } } } char tmp[20010]; int main(){ //freopen("D:/a.txt", "r", stdin); int n, q; while (~scanf("%d", &n)){ init(); getchar(); for (int i=1; i<=n; i++) buf[i].get(i); sort(buf+1, buf+1+n); scanf("%d", &q); for (int i=1; i<=q; i++){ scanf("%s", tmp); ins(tmp, i); } makefail(); for (int i=1; i<=n; i++) ac(buf[i].s.c_str(),buf[i].id); for (int i=1; i<=q; i++){ if (ans[i].size()==0)printf("-1\n"); else for (int j=0; j<ans[i].size(); j++) printf("%d%c", ans[i][j], j==ans[i].size()-1?'\n':' '); } } return 0; }