toj1205 Compound Words

来源:互联网 发布:淘宝店铺logo设计素材 编辑:程序博客网 时间:2024/05/23 21:40
1205.   Compound Words
Time Limit: 3.0 Seconds   Memory Limit:65536K
Total Runs: 1108   Accepted Runs:344



You are to find all the two-word compound words in a dictionary. A two-word compound word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary.


Input

Standard input consists of a number of lowercase words, one per line, in alphabetical order. There will be no more than 120,000 words.


Output

Your output should contain all the compound words, one per line, in alphabetical order.


Sample Input

aalienbornlesslienneverneverthelessnewnewbornthezebra


Sample Output

aliennewborn
#include <cstdio>#include <cstring>#include <cstdlib>#include <vector>#include <algorithm>using namespace std;const int MAX = 120000+74; //明天七夕了...const int PR = 700007;const int LEN = 64;char str[MAX][LEN];char hash[PR][LEN];bool vis[PR];int len[MAX];int n;vector<const char*> ans;bool cmp(const char* str1, const char* str2) {int t = strcmp(str1, str2);return strcmp(str1, str2) < 0;}inline void Insert(int id){//iprintf("get %s\n", str[id]);char* s = str[id];int l = len[id];int key = 0;for (int i = 0; i < l; ++i) {key *= 128;key += s[i];if (key > PR) key %= PR;}//printf("key = %d\n", key);int k = 1;while (vis[key]) {key += k*k;if (key > PR) key %= PR;//printf("key = %d\n", key);++k;}vis[key] = true;//printf("Insert %s to pos.%d\n", str[id], key);strcpy(hash[key], str[id]);}inline bool hav(const char* s) {int len = strlen(s), key = 0, k = 1;for (int i = 0; i < len; ++i) {key *= 128;key += s[i];if (key > PR) key %= PR;}while (vis[key]) {if (strcmp(s, hash[key]) == 0) return true;key += k*k;if (key > PR) key %= PR;++k;}return false;}/*int cmp(const void* str1, const void* str2) {return strcmp((char*)str1, (char*)str2);}*/bool myfun (const char* str1, const char* str2) {return strcmp(str1, str2) == 0;}int main() {memset(vis, false, sizeof(vis));char s[LEN], strl[LEN], strr[LEN];n = 0;while (~scanf(" %s", str[n])) {len[n] = strlen(str[n]);Insert(n);++n;}//iqsort(str, n, sizeof(char)*LEN, cmp);//puts("flag1");for (int i = 0; i < n; ++i) {for (int j = 1; j < len[i]; ++j) {strncpy(strl, str[i], j);strl[j] = '\0';strcpy(strr, str[i]+j);//printf("get: %s&%s\n", strl, strr);if (hav(strl) && hav(strr))ans.push_back(str[i]);//puts(str[i]);}}//puts("flag2");sort(ans.begin(), ans.end(), cmp);vector<const char*>::iterator tmp = unique(ans.begin(), ans.end(), myfun);ans.erase(tmp, ans.end());for (vector<const char*>::iterator it = ans.begin();it != ans.end(); ++it) {puts(*it);}return 0;}



Source: Waterloo Local Contest Sep. 28, 1996


俺觉得俺们学校OJ的AC最漂酿:14389652014-08-02 09:23:54Accepted1205C++2.2K0'00.05"53356K
奏是要红色的嘛...


这题是一道很裸的散列表.也就是hash表(哈希).
题目大意是给定很多个单词,让你把里面由其它两个单词组成的单词输出.比如字典里有a, lien, alien那这个alien是由字典中其它两个单词a和lien组成的,就是我们要找的了.
首先思路很简单,我们要把这些单词保存好,然后对其中某个单词,比如alien,我们依次剖分成(a,lien),(al,ien),(ali,en),(alie,n)然后分别找是否同时存在这四组单词就好了,只要有一组
存在,alien就可以是答案.然后直接丢到set或者vector中.
但是单词数量庞大,可能达到12万,而且很坑爹的是题目没有说每个单词的长度,数组都不好开.你可能想用string了~~~确实如此!我们用string,然后排序,排序规则呢?可以先按长度
再按字典序排,这么一来每个单词我们都只需查找它前面那部分就可以了,比如a,lien一定都排在alien前面的. 查找时可以用二分查找.而且为了方便你还可以把每个单词换算成
一个数字,这样方便许多,但是如果单词很长这么搞基本不现实,因为就是long long也搞不定啊...所以更麻烦的方法是手动写二分查找.最后得到的字符串直接插到set中,利用set无法
插入相同元素我们甚至不需要考虑重复单词(为什么?想想这组数据:ab,a,b,ab,ab,我们得到3个ab是不是应该消除重复?),用vector就需要先排序然后用unique消除重复元素了...(参考cplusplus.com).
另一种办法,就是用hash表,插入和查找都是log(n)而且省去了二分的纠结,除非你自信你手写的二分没有bug...
我在这用的hash表,就是比如一个单词alien,看做一个128进制数(因为ASCII码最多128,其实26进制足矣),转换成一个十进制数key,然后存到数组hash[key]的位置,当然中间过程
还是要解决冲突和取模
0 0
原创粉丝点击