描述
给定n个字符串,再询问m次,每个询问给出一个字符串,求出这个字符串是n个字符串里,多少个串的前缀。
前缀:从头开始的一段连续子串。比如字符串ab是字符串abcd的前缀,也是字符串ab(自身)的前缀,但不是bab的前缀。
输入
第一行包含两个正整数n,m。
接下来n行,每行表示一个字符串,表示给定的n个字符串中的一个。
再接下来m行,每行一个字符串,表示询问的字符串。
输出
输出m行,每行表示询问的答案。
样例输入
5 4
ab
abc
ab
ba
bb
a
b
ab
abc
样例输出
3
2
3
1
样例解释
字符串a是ab、abc、ab的前缀;
字符串b是ba、bb的前缀;
字符串ab是ab、abc、ab的前缀;
字符串abc是abc的前缀。
提示
[trie树基本题。]
一. 伪代码
二. 具体实现(C++)
#include <bits/stdc++.h>using namespace std;
// ================= 代码实现开始 =================
const int M = 505, L = 1000005;
// c:trie树上的边,c[x][y]表示从节点x出发(x从1开始),字符为y的边(y范围是0到25)
// sz:sz[x]表示x节点的子树中终止节点的数量(子树包括x自身)
// cnt:trie树上节点的数目
int c[L][26], sz[L], cnt;
// 将字符串s加入到trie树中
// s:所要插入的字符串
void add(char *s) {
int x =0;
for(;*s;++s){
int y = *s -'a';
if(!c[x][y])
c[x][y] = ++cnt;
x=c[x][y];
}
++sz[x];
}
// 用于计算sz数组
// x:当前节点
void dfs(int x) {
for(int y=0; y<26; ++y){
int z = c[x][y];
if(z!=0){
dfs(z);
sz[x] += sz[z];
}
}
}
// 用字符串s沿着trie树上走,找到相应的节点
// s:所给字符串
// 返回值:走到的节点
int walk(char *s) {
int x = 0;
for(; *s; ++s){
int y = *s - 'a';
if(!c[x][y])
return 0;
x = c[x][y];
}
return x;
}
// ================= 代码实现结束 =================