链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31480
题意:给n个单词及其出现的频率,给m个前缀,找出一次为前缀的单词中频率为前10的。数据范围:1<=n<=10^5,1<=m<=15000,每个单词长度不超过15。
题解:做法一:trie树,维护一个vector<int> ans来记录结果。先对n个单词用先按频率排序,频率相同按字典序排序。然后将这m个前缀插入trie树中。然后将n个单词插入trie树。在插入的时候记得更新每个节点的ans。如果ans.size()>=10就不更新了。因为这n个单词已经排好序了。对于一这个节点为前缀的频率前10的字符串一定先插入字典树。。然后输出即可。
做法二:Hash+二分。先坑着~~~~~~。。。
代码君:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int maxn = 16;
struct Data {
char str[maxn];
int fre;
};
struct Node {
Node *next[26];
vector<int> ans;
int cnt;
};
int tot;
Data data[100100];
Node pool[15555*maxn], *root;
bool cmp(int a, int b) {
if (data[a].fre != data[b].fre)
return data[a].fre > data[b].fre;
return strcmp(data[a].str, data[b].str) < 0;
}
Node *newNode() {
Node *p = &pool[tot++];
memset(p->next, 0, sizeof(p->next));
p->ans.clear();
p->cnt = 0;
return p;
}
void init() {
tot = 0;
root = newNode();
}
void insert(char buf[]) {
Node *cur = root;
for (int i = 0; buf[i]; i++) {
int ch = buf[i] - 'a';
if (!cur->next[ch])
cur->next[ch] = newNode();
cur = cur->next[ch];
}
}
void query(char buf[], int id) {
Node *cur = root;
for (int i = 0; buf[i]; i++) {
int ch = buf[i] - 'a';
if (!cur->next[ch])
return ;
cur = cur->next[ch];
if (cur->ans.size() >= 10)
continue;
cur->ans.push_back(id);
}
}
void output(char buf[]) {
Node *cur = root;
for (int i = 0; buf[i]; i++) {
int ch = buf[i] - 'a';
cur = cur->next[ch];
}
for (int i = 0; i < cur->ans.size(); i++)
printf("%s\n", data[cur->ans[i]].str);
}
int n, k, idx[100010];
char buf[15555][maxn];
void input() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%s %d", data[i].str, &data[i].fre);
idx[i] = i;
}
sort(idx, idx + n, cmp);
init();
scanf("%d", &k);
for (int i = 0; i < k; i++) {
scanf("%s", buf[i]);
insert(buf[i]);
}
}
void solve() {
input();
for (int i = 0; i < n; i++)
query(data[idx[i]].str, idx[i]);
for (int i = 0; i < k; i++) {
if (i) puts("");
output(buf[i]);
}
}
int main() {
solve();
return 0;
}