Trie模板。把所有单词都用字典树存起来,然后给每个节点赋权值表示前缀到该节点出现了几次。然后直接查询就可以了。
#include <algorithm> #include <iostream> #include <sstream> #include <cstdlib> #include <climits> #include <cstring> #include <cstdio> #include <string> #include <vector> #include <cctype> #include <queue> #include <cmath> #include <set> #include <map> #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int MAX_NODE = 10100 * 66; const int INF = 0x3f3f3f3f; const int MOD = 20090717; const int CHILD_NUM = 26; const int N = 30; class Trie { private: int chd[MAX_NODE][CHILD_NUM]; int val[MAX_NODE]; int Q[MAX_NODE]; int ID[128]; int sz; public: void Initialize() { for(int i = 0; i < 26; i ++) ID[i + 'a'] = i; } void Reset() { CLR(chd[0] , 0);sz = 1; CLR(val, 0); } void Insert(char *a) { int p = 0; for ( ; *a ; a ++) { int c = ID[*a]; if (!chd[p][c]) { CLR(chd[sz] , 0); chd[p][c] = sz ++; } p = chd[p][c]; val[p] ++; } } int Work() { int q, now, S = 0; double tmp[10], lg; scanf("%d", &q);bool flag = 0; for(int i = 0; i < q; i ++) { lg = 1e18; for(int j = 0; j < 8; j ++) { scanf("%lf", &tmp[j]); lg = min(lg, tmp[j]); }now = 0; for(int j = 0; j < 8; j ++) { now <<= 1; if(tmp[j] > lg * 1.105) now += 1; } if(!flag)S = chd[S][ID[now]]; if(!S) flag = 1; } if(!flag) return val[S]; else return 0; } } Tr; char ch[N]; int main() { //freopen("input.txt", "r", stdin); Tr.Initialize(); int n, m, k, ans; while (scanf("%d%d", &n, &m) != EOF) { Tr.Reset(); for (int i = 0 ; i < n ; i ++) { char temp[66]; scanf("%s", temp); Tr.Insert(temp); } ans = 0; for(int i = 0; i < m; i ++) ans += Tr.Work(); printf("%d ", ans); } return 0; }