思路:字典树
分析:
1 题目给定n个单词,有m次的询问。每一次的询问会有k个长度为8的条形码,条形码是8个double组成。现在要求将条形码转化为字符串然后求出n个单词中以该字符串为前缀的个数,最后把m次询问结果相加。
2 利用字典树在节点里面存储以某一个子串为前缀的单词的个数;接下来就是怎样把条形码转化为字符串,由于题目明确指出只有两种的宽度,并且有两倍的关系。但是由于存在误差,所以输入的数据是有差的;其实我们只要求出8个数的总和然后求平均值,那么肯定就有比平均值小的肯定用0表示,比平均值大的肯定用1表示,为什么呢(因为误差的范围只在(0.95-1.05))。所以这样就可以解决问题。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define eps 1e-9
#define MAXN 1000010
#define MAX 40
#define N 30
int cnt , n , m , k;
int ans;
struct Trie{
int count;
Trie *child[N];
}trie[MAXN];
Trie *root;
/*节点的空间分配*/
Trie *newTrie(){
trie[cnt].count = 0;
for(int i = 0 ; i < N ; i++)
trie[cnt].child[i] = NULL;
return &trie[cnt++];
}
/*字典树的插入*/
void insert(char *str){
Trie *s = root;
int len = strlen(str);
for(int i = 0 ; i < len ; i++){
int num = str[i]-'a';
if(s->child[num] == NULL)
s->child[num] = newTrie();
s = s->child[num];
s->count++;
}
}
/*字典树的查找*/
int search(char *str){
Trie *s = root;
int len = strlen(str);
for(int i = 0 ; i < len ; i++){
int num = str[i]-'a';
if(s->child[num] == NULL)
return 0;
s = s->child[num];
}
return s->count;
}
int main(){
int i , j;
char words[MAX];
double num[8];
double sum;
int number;
while(scanf("%d%d" , &n , &m) != EOF){
ans = 0;
cnt = 0;
root = newTrie();
/*输入单词*/
for(i = 0 ; i < n ; i++){
scanf("%s" , words);
insert(words);
}
/*输入m次的询问*/
for(i = 0 ; i < m ; i++){
scanf("%d" , &k);
memset(words , '\0' , sizeof(words));
for(j = 0 ; j < k ; j++){
sum = 0.0;
for(int t = 0 ; t < 8 ; t++){
scanf("%lf" , &num[t]);
sum += num[t];
}
/*求要搜素的字符串*/
sum /= 8;
number = 0;
for(int t = 0 ; t < 8 ; t++){
if(num[t]-sum > eps)
number += pow(2.0 , 7-t);
}
char c = number;
words[j] = c;
}
ans += search(words);/*相加*/
}
printf("%lld\n" , ans);
}
return 0;
}