int son[N][26];//代表每个节点可以有26个子节点 int cnt[N];//以当前这个点结尾的字符串有多少个 int idx;//操作次数,当前用到了哪个下标 //下标是0的点,既是根节点,也是空节点 char str[N];
voidinsert(char str[])//插入新字符串 { int p = 0;//根节点 for (int i = 0;str[i];i++) { int u = str[i] - 'a';//存储编号,字母a-'a'就变成了0,b就变成了1 //如果说该节点之后没有这个字母,即son[p][u] == 0 if (!son[p][u]) son[p][u] = ++idx;//把这个节点加进去 p = son[p][u]; }
cnt[p]++;//表示以该点结尾的数量又多了一个 }
intquery(char str[])//查询字符串 { int p = 0; for (int i = 0;str[i];i++) { int u = str[i] - 'a'; if (!son[p][u]) return0;//如果不存在直接返回0 p = son[p][u] ; }
return cnt[p];//返回以该节点结尾的单词数量 } intmain() { int n; scanf("%d", &n); while (n--) { char op[2];//操作类型+空格 scanf("%s%s", op,str);
if (op[0] == 'I') insert(str);//插入操作 elseprintf("%d\n", query(str));//查询操作 }
return0; }
习题
暴力做法
利用两重for循环来寻找最大异或
//暴力法 for (int i = 0;i < n;++i) { for (int j = 0; j < i;++j) res = max(res, (arr[i] ^ arr[j])); }
voidinsert(int x) { int p = 0;//尾节点 for (int i = 30;i >= 0;--i) { int u = x >> i & 1;//得到该位 if (!son[p][u]) son[p][u] = ++idx; p = son[p][u]; } }
intquery(int x) { int p = 0; int res = 0; for (int i = 30;i >= 0;i--) { int u = x >> i & 1; //如果该位相异的数存在 if (son[p][!u]) { p = son[p][!u]; res = res * 2 + !u;//相当于把所有的位数进一再加上u } else { p = son[p][u]; res = res * 2 + u; } }
return res; } intmain() { int n; scanf("%d", &n);
for (int i = 0;i < n;++i) scanf("%d", &arr[i]);
int res = 0;
for (int i = 0;i < n;++i) { insert(arr[i]); //先插入在查询,防止第一次查询不到的情况 int t = query(arr[i]);
res = max(res, (arr[i] ^ t)); } printf("%d", res); }