题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4287
题意:根据手机的输入法可以知道
2:a,b,c
3:d,e,f
4:g,h,i
5:j,k,l
6:m,n,o
7:p,q,r,s
8:t,u,v
9:w,x,y,z
先给n个串由数字构成,然后m个串由字母构成。
对于每个数字串,判断可以包含几个字母串,并输出。
思路:用数字串建字典树,在每个数字串的结尾的节点记录好该数字串包含字母串的个数。预处理好每个字母所属于的数字,然后在字典树中查找字母串,并在数字串的结尾节点计数。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ceil(x, y) (((x) + (y) - 1) / (y))
const int SIZE = 10;
const int N = 5e5 + 10;
const int INF = 0x7f7f7f7f;
struct Trie {
int val[SIZE];
int count;
};
int sz;
int len[SIZE] = {3, 3, 3, 3, 3, 4, 3, 4};
int vis[SIZE * 3];
Trie pn[N];
string str[N];
int newnode() {
memset(pn[sz].val, 0, sizeof(pn[sz].val));
pn[sz].count = 0;
return sz++;
}
void init() {
sz = 0;
newnode();
memset(vis, false, sizeof(vis));
int k = 0;
for (int i = 0; i < 8; i++)
for (int j = 0; j < len[i]; j++)
vis[k++] = i + 2;
}
void insert(string s) {
int u = 0;
for (int i = 0; i < s.size(); i++) {
int idx = s[i] - '0';
if (!pn[u].val[idx]) {
pn[u].val[idx] = newnode();
}
u = pn[u].val[idx];
}
}
void findpre(string s) {
int u = 0;
for (int i = 0; i < s.size(); i++) {
int idx = s[i] - 'a';
if (!pn[u].val[vis[idx]])
return ;
u = pn[u].val[vis[idx]];
}
pn[u].count++;
}
int findstr(string s) {
int u = 0;
for (int i = 0; i < s.size(); i++) {
int idx = s[i] - '0';
u = pn[u].val[idx];
}
return pn[u].count;
}
int main() {
int t_case;
cin >> t_case;
for (int i_case = 1; i_case <= t_case; i_case++) {
int n, m;
cin >> n >> m;
init();
for (int i = 0; i < n; i++) {
cin >> str[i];
insert(str[i]);
}
for (int i = 0; i < m; i++) {
string t;
cin >> t;
findpre(t);
}
for (int i = 0; i < n; i++)
cout << findstr(str[i]) << endl;
}
return 0;
}