SYSU-7, Gym 100273J, trie+hash
cnm毛子的题是正宗内家拳法啊orz(捶地),拼的就是智商,这题我们队想了老半天后缀自动机,掏出各种黑科技无果
题目大意:构建一个自动机可以表达给定的n个串,询问最小的自动机节点树为多少。
解:最裸的自动机其实就是一棵trie,那么我们考虑优化这棵trie,考虑拓扑排序倒过来做,可以发现其实如果两个节点如果他们指向的节点状态完全一致,那么这两个节点是等价的,所以我们不断合并这些节点即可。但是拓扑可能会慢,而且貌似会退化n方(没细想),但一般地,我们用dfs出栈序去做这个hash去重即可。
cnm居然hash冲突orz。。。。早知道就不hash成一个值而是学2队 所有儿子状态弄成一个结构丢进map里算了。如果赛场上这样写wa了根本调不出来,就要背大锅了。
1 #include <cstdio> 2 #include <string> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <cstring> 7 #include <complex> 8 #include <set> 9 #include <vector> 10 #include <map> 11 #include <queue> 12 #include <deque> 13 #include <ctime> 14 15 using namespace std; 16 17 const double EPS = 1e-8; 18 19 #define ABS(x) ((x)<0?(-(x)):(x)) 20 #define SQR(x) ((x)*(x)) 21 #define MIN(a,b) ((a)<(b)?(a):(b)) 22 #define MAX(a,b) ((a)>(b)?(a):(b)) 23 24 #define LSON(x) ((x)<<1) 25 #define RSON(x) (((x)<<1)+1) 26 #define LOWBIT(x) ((x)&(-(x))) 27 #define MAXS 1111 28 #define MAXN 222222 29 #define VOIDPOINT 0 30 #define LL long long 31 #define OO 214748364 32 33 #define MAXT 11 34 35 const LL MOD = 1e11+9; 36 37 LL poww[111]; 38 39 struct node{ 40 node *ch[26]; 41 int lab, isWord; 42 LL hash; 43 }; 44 map <LL, node* > mp; 45 46 struct TrieTree{ 47 node t[MAXN], *root; 48 int cnt; 49 node* newNode() { 50 node *u = &t[++cnt]; 51 memset(u, 0, sizeof(t[0])); 52 u->lab = cnt; 53 return u; 54 } 55 void clear() { 56 root = &t[0]; 57 cnt = 0; memset(t, 0, sizeof(t[0])); 58 } 59 void insert(const char *str) { 60 int len = strlen(str); 61 node *u = root; 62 for (int i = 0; i < len; ++i) { 63 if (u->ch[str[i] - 'a'] == 0) { 64 u->ch[str[i] - 'a'] = newNode(); 65 } 66 u = u->ch[str[i] - 'a']; 67 } 68 u->isWord = 1; 69 } 70 } Trie; 71 72 void dfs(node *&u) { 73 LL res = 0; 74 for (int i = 0; i < 26; ++i) { 75 if (u->ch[i]) { 76 dfs(u->ch[i]); 77 } 78 res = (res * (1LL << 22) + (u->ch[i] ? u->ch[i]->lab : MAXN+1)) % MOD; 79 } 80 // cout << u->lab << ' '<< res << endl; 81 // for (int i = 0; i < 26; ++i) 82 // cout << (u->ch[i] ? u->ch[i]->lab : -1) << ' '; cout << endl; 83 res = (res * 2 + u->isWord) % MOD; 84 u->hash = res; 85 if (mp.count(u->hash) == 0) { 86 mp[u->hash] = u; 87 } else 88 u = mp[u->hash]; 89 } 90 91 char str[MAXS]; 92 93 int main() { 94 freopen("test.txt", "r", stdin); 95 // freopen("language.in", "r", stdin); freopen("language.out", "w", stdout); 96 97 Trie.clear(); 98 int n; 99 scanf("%d", &n); 100 for (int i = 0; i < n; ++i) { 101 scanf("%s", str); 102 Trie.insert(str); 103 } 104 105 mp.clear(); 106 dfs(Trie.root); 107 108 cout << mp.size() << endl; 109 110 fclose(stdin); 111 fclose(stdout); 112 return 0; 113 }