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()); } }