// hdu 2846 Repository 字典树 // // 题目大意: // // 有n个字符串,m个待询问的字符串,问这些字符串里面以该询问的 // 字符串为子串的字符串有多少个 // // 解题思路: // // 字典树,将字符串的所有子串插入到字典树中,并设立一个No.标识 // 以免重计数。最后查询就好了 // // 感悟: // // 这题的数据量有点大,虽然p是10000,但是长度是20,单个字符串的 // 最大子串数粗略的估计是 20 * 20 ,所以开的空间也要比较大。开始 // 开的是30w,返回了wa,开了40w,还是返回wa,开了50w,结果轻松Ac // 啦~,继续加油哟~~~FIGHTING #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 500000; struct Trie{ int ch[MAX_N][26]; int sz; int val[MAX_N]; int no[MAX_N]; void init(){ sz = 1; memset(ch[0],0,sizeof(ch[0])); val[0] = 0; no[0] = 0; } int idx(char c){ return c - 'a'; } void insert(char *s,int st,int ed,int v){ int u = 0; //int n = strlen(s); for (int i=st;i<=ed;i++){ int c = idx(s[i]); if (no[u]!=v) // 这里是为了不重复计数,如果插入的点 val[u]++; // 是当前的串的子串,所有的该串子串都 // 会有特定的v的标记,碰到了就避免计数 if (!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; no[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } if (no[u]!=v) // 不要忘了在插入的末尾,可能还会有相同的子串诺 val[u]++; no[u] = v; } int query(char *s){ int u = 0; int n = strlen(s); for (int i=0;i<n;i++){ int c = idx(s[i]); if (!ch[u][c]){ return 0; } u = ch[u][c]; } return val[u]; } }trie; void print(char *s,int st,int ed,int num){ printf("%d \n\n",num); for (int i=st;i<=ed;i++){ printf("%c",s[i]); } cout << endl; } int n,m; bool vis[10009]; void input(){ trie.init(); char s[30]; for (int i=1;i<=n;i++){ scanf("%s",s); int len = strlen(s); for (int j=len-1;j>=0;j--){ for (int k=j;k<len;k++){ trie.insert(s,j,k,i); //print(s,j,k,i); } } } scanf("%d",&m); for (int i=1;i<=m;i++){ scanf("%s",s); printf("%d\n",trie.query(s)); } //memset(vis,0,sizeof(vis)) } int main(){ //freopen("1.txt","r",stdin); while(scanf("%d",&n)!=EOF){ input(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 16:15:40