暑假集訓Day 7 馬大嘴的廢話(trie樹)

題目大意

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

算法分析

  • n爲10000 m爲100000的數據顯然暴力枚舉每個字符串是過不去的
  • 這裏就要用到咱們的trie樹(字典樹,前綴樹)了
  • 首先咱們用輸入的n個字符串建樹 建樹方法在trie專題中有 這裏就再也不贅述
  • 惟一須要注意的點就是判重 在下面的代碼中註釋有體現
  • 註釋挺全面的看註釋吧(其實我真的不是懶

代碼展現

#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());
	}
}
相關文章
相關標籤/搜索