/*
    N<=10000个文本串,M<=10000个要查询的串
    对每个要查询的串,有多少个文本串与该串的编辑距离<=1
    若编辑距离为0,输出-1

    建立Trie树,对于要查询的串,状态(root, p, change)
    表示当前在节点root,查询的串检查到p,change表示有没修改过
    ------root及p之前的都匹配了,当前就是root的儿子跟p检查了

    有匹配,添加,删除,替换
    注意的是,查询的是文本串的个数,因为可能不同的变换,会导致到达同一个状态
    -------需要判重,一方面加快速度,另一方面不会重复计数
    大数组判重,每次清空的话会很花时间,用cases数标记一下,表示在当前这个case
    已经访问过

    注意到达最后时,*p == 0 时,这个位置还可以再插入的,不要立即返回了

    hit 2888是升级版
    是求前缀,要注意重复计数,还有清空问题等
*/

#include
<iostream>
#include
<cstring>
#include
<map>
#include
<algorithm>
#include
<stack>
#include
<queue>
#include
<cmath>
#include
<string>
#include
<cstdlib>
#include
<vector>
#include
<cstdio>
#include
<set>
#include
<list>
#include
<numeric>
#include
<cassert>
#include
<ctime>

using namespace std;

const int MAXN = 200010;

struct Trie {
    
int cnt;
    Trie 
*ch[26];
}
;

Trie nodes[MAXN], 
*ptr, *root;

char str[30];
int mark[MAXN][21][2], cases;

Trie
* newNode(){
    ptr
->cnt = 0;
    fill(ptr
->ch,  ptr->ch+26, (Trie*)NULL);//
    return ptr++;
}


void insert(Trie *root, char *p) {
    
if (*== 0{
        root
->cnt ++;
        
return ;
    }

    
if (root->ch[*p-'a'== NULL) {
        root
->ch[*p-'a'= newNode();
    }

    insert(root
->ch[*p-'a'] , p+1);
}



int gao(Trie *root, char *p , int change) {
    
if(mark[root-nodes][p-str][change>0== cases){
        
return 0;
    }

    mark[root
-nodes][p-str][change>0= cases;
    
if (*== 0{
        
int tot = root->cnt;
        
if!change ) {
            
if( root->cnt > 0 ) {
                
return -1;
            }

            
for ( int i = 0; i < 26; i++// add at last
                if( root->ch[i] != NULL) {
                    tot 
+= root->ch[i]->cnt;
                    mark[root
->ch[i]-nodes][p-str][1= cases;//note!!!!
                }

            }

        }

        
return tot;
    }


    
int tot = 0;
    
//match *p
    if (root->ch[*p-'a'!= NULL) {
        
int tmp = gao(root->ch[*p-'a'] , p+1, change);
        
if (tmp == -1{
            
return -1;
        }

        tot 
+= tmp;
    }

    
if(!change) {
        
//del
        tot += gao(root, p+11);
        
for (int i = 0; i < 26; i++{
            
if (root->ch[i] != NULL ) {
                
//add
                tot += gao(root->ch[i], p , 2);
                
if( i != *p-'a'){
                    
//replace
                    tot += gao(root->ch[i], p+1 , 4);
                }

            }

        }

    }

    
return tot;
}


int main()
{

#ifndef ONLINE_JUDGE
    freopen(
"in","r",stdin);
#endif

    
for ( int n, m; ~scanf("%d%d"&n, &m); ) {
        ptr 
= nodes;
        root 
= newNode();
        
for (int i = 0; i < n ; i++{
            scanf(
"%s", str);
            insert(root, str);
        }

        
for (int i = 0 ;i < m; i++{
            cases
++;
            scanf(
"%s", str);
            printf(
"%d\n", gao(root, str, 0));
        }

    }

    
return 0;
}



以下是hit 2888的核心部分
/*
    对于串str,经过一些变换,
    if (*p == 0) 说明匹配了,这个根到这个节点就是一个合法的前缀了
    所以状态 (root, p, edth) 当前树的节点root,串匹配到p(p之前的已经和root及之前的匹配了),可用距离edth
    如果某个节点已经mark为2,表明它被某种变换匹配了,就不用继续搜了
    if (root->mark == 2) {
        return;
    }
    这里又不是求变换的方法数,所以之前的变换已经可行了,当前的这种变换不用搞下去了,直接return
    然后对走过的路径mark为1,为了以后找到这些走过的节点,计算总数,还有清空,避免走无用的位置
    
    注意某个节点mark为2,有可能它下面的某个节点也被mark为2,要注意只保留离根最近的那个
*/


void gao(Trie *root, char *p , int edth) {
    
    
if (root->mark == 2{
        
return;
    }

    root
->mark = 1;
    
if (*== 0{
        root
->mark = 2;
        
return ;
    }

    
//match *p
    if (root->ch[*p-'a'!= NULL) {
        gao(root
->ch[*p-'a'] , p+1, edth);
    }

    
if(edth > 0{
        
//del
        gao(root, p+1, edth - 1);
        
for (int i = 0; i < 26; i++{
            
if (root->ch[i] != NULL) {
                
//add
                gao(root->ch[i], p , edth - 1);
                
if( i != *p-'a'){
                    
//replace
                    gao(root->ch[i], p+1 , edth - 1);
                }

            }

        }

    }

    
return ;
}


int gao(Trie *root) {//cal and clear
    if (root -> mark == 0{
        
return 0;
    }

    
int ans = 0;
    
for (int i = 0; i < 26 ; i ++{//mark为2,也有可能下面的节点也有2,要继续清空
        if (root->ch[i] != NULL) {
            ans 
+= gao(root->ch[i]);
        }

    }

    
if (root->mark == 2){//只保留离根最近的那个值
        ans = root->cnt;
    }

    root
->mark = 0;
    
return ans;
}