// 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;
}
hdu 2846 Repository 字典树
最新推荐文章于 2019-01-08 00:08:43 发布