众所周知,讯飞输入法具备强大的学习功能,对于用户来说,感觉输入法像一个会学习的机器人,比如,当用户第一次输入“sxl”,输入法第一个提示“少写了”,
如果用户选择“睡醒了”,当第二次用户再输入“sxl”的时候,“睡醒了”这个词就会出现在比较靠前的位置,神奇吧,输入法就像一个小孩子,在你的指导下慢慢学会每个拼音的含义。
现在让我们一起来实现下这个神奇的功能吧,为方便起见,我们假设用户是美国籍的(仅输入小写英语字母),每当该用户输入一个单词时,请输出和该用户输入习惯最为匹配的单词(以该单词为前缀的输入频率最高的单词),如果有多个则输出字典序最小的,如果没有的话,则直接输出该单词。
就是校赛的那道字典树模板提啦。当初我是用猥琐的二分水过的,事实证明那其实是bo神忘记加了一组可以卡掉我代码的数据而已,事实上这种数据还很好构造o(╯□╰)o
正好最近在学习字典树,就用字典树重写了一遍,记录以一个节点为根节点的子树中频率最大的节点,应该是比较基础的字典树题目啦
一开始按照bo神教我的写法是2.1s,后来发现只要把STL的stack改成自己模拟的就只要900ms了,看来STL不能乱用啊,估计是我把stack声明在循环体里面,每次循环的时候都要new和析构一下,消耗了许多时间吧。
最后Orz一下Wzy的511ms
1 #include <cstdio> 2 #include <sstream> 3 #include <fstream> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 #include <map> 8 #include <cctype> 9 #include <ctime> 10 #include <set> 11 #include <climits> 12 #include <vector> 13 #include <queue> 14 #include <stack> 15 #include <cstdlib> 16 #include <cmath> 17 #include <string> 18 #include <list> 19 20 #define INPUT_FILE "in.txt" 21 #define OUTPUT_FILE "out.txt" 22 23 using namespace std; 24 25 typedef long long LL; 26 const int INF = INT_MAX / 2; 27 28 void setfile() { 29 freopen(INPUT_FILE,"r",stdin); 30 freopen(OUTPUT_FILE,"w",stdout); 31 } 32 33 const int maxn = 100000; 34 const int maxlen = 11; 35 const int maxnode = maxn * (maxlen - 1); 36 const int sigma_size = 26; 37 38 char buf[maxn + 1][maxlen]; 39 40 struct tnode { 41 int next[sigma_size],times,most,val,from; 42 char letter; 43 }; 44 45 tnode node[maxnode]; 46 int path[15],top = 0; 47 int sz; 48 49 50 int main() { 51 int n; scanf("%d",&n); 52 //初始化trie树 53 sz = 1; 54 memset(&node[0],0,sizeof(tnode)); 55 node[0].from = -1; 56 //处理输入 57 for(int i = 1;i <= n;i++) { 58 scanf("%s",buf[i]); 59 //插入trie树 60 int len = strlen(buf[i]),u = 0; 61 top = 0; 62 for(int j = 0;j < len;j++) { 63 path[top++] = u; //记录路径 64 int c = buf[i][j] - 'a'; 65 if(node[u].next[c] == 0) { 66 memset(&node[sz],0,sizeof(tnode)); 67 node[sz].letter = c; 68 node[sz].from = -1; 69 node[sz].most = sz; 70 node[u].next[c] = sz++; 71 } 72 u = node[u].next[c]; 73 } 74 if(node[u].times == 0) { 75 node[u].val = i; 76 } 77 node[u].times++; 78 //输出单词 79 printf("%s ",buf[node[node[u].most].val]); 80 //更新节点自身 81 if(node[u].times >= node[ node[u].most ].times) { 82 node[u].most = u; node[u].from = -1; 83 } 84 while(top > 0) { 85 //向上依次更新每一个经过的节点的最大子树 86 int fa = path[--top]; 87 int fmost = node[fa].most; 88 int umost = node[u].most; 89 if(node[umost].times > node[fmost].times //子节点的最大频率值比父节点的大 90 || (node[umost].times == node[fmost].times && (node[u].letter <= node[fa].from))) //频率相等但是字典序靠前 91 { 92 node[fa].most = umost; 93 node[fa].from = node[u].letter; 94 } else break; 95 u = fa; 96 } 97 } 98 return 0; 99 }