思路:字典树
分析:
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; }
时间: 2024-12-24 21:18:52