MZH爱说废话,喜好“水群”,常常被“提走”,管理员对MZH在群里说话进行了限制:c++
一、只能说小写英文字母。算法
二、长度不超过20。spa
即便这样,也不能阻止MZH“水群”,他在限制的条件下也说了成千上万条废话信息,如今已知MZH说过的N条废话信息,接下来MZH要说M条废话信息,请你回答:对于他说的每条废话信息在已知N条废话信息中出现的次数和(若是一条中出现屡次,只算一次)。code
好比:MZH说过了3条信息
1.adbdb字符串
2.bcdeit
3.cdbfclass
4.db方法
如今说的信息为db,那么信息db在信息1和信息3和信息4出现过,因此答案为3.数据
第一行,一个整数N。db
接下来N行,每行一个字符串(只能由小写字母组成),表明MZH说过的N条废话信息。
再接下来一行,一个整数M。
接下来M行,每行一个字符串(只能由小写字母组成),表明当前MZH要说的一条废话信息。
共M行,每行输出该废话信息出现的次数和。
20 ad ae af ag ah ai aj ak al ads add ade adf adg adh adi adj adk adl aes 5 b a d ad s
0 20 11 11 2
20%的数据:n<=100 , m<=50
60%的数据:n<=10000, m<=500
100%的数据:n<=10000, m<=100000
#include<bits/stdc++.h> using namespace std; const int maxn = (1e4+10)*50; int tree[maxn][26],v[maxn][26],cnt[maxn][26],len,tot; char s[26]; void add(int l, int r, int id){ int rt = 0,t; while(l < r){//由于要看是否存在于字符串中而不是 是否为前缀 因此要把一个字符串以每一个字符为起点存一次 t = s[l] - 'a';//将字母转化为对应的下标 if (tree[rt][t]) {//若是当前的字母已经建过节点 if (v[rt][t] != id) { v[rt][t] = id; ++cnt[rt][t];//当前字符串++ } } else {//若是尚未建过当前节点 tree[rt][t] = ++tot;//新建一个点 v[rt][t] = id; cnt[rt][t]++; } rt = tree[rt][t]; ++l; } } int search(){ int rt = 0,ans = 0; for(int i = 0;i < len;++i){ if(!tree[rt][s[i]-'a'])return 0;//若是当前字符未出现过 ans = cnt[rt][s[i]-'a'];//即为当前字符串出现的次数 rt = tree[rt][s[i]-'a'];//为下一次转移作准备 } return ans; } int main(){ int n;scanf("%d",&n); for(int i = 0;i < n;++i){ scanf("%s",s); len = strlen(s); for(int j = 0;j < len;++j){ add(j,len,i); } } int m;scanf("%d",&m); while(m--){ scanf("%s",s); len = strlen(s); printf("%d\n",search()); } }