HDU5269 字典树

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5269 ,BestCoder Round #44的B题,关于字典树的应用。

  比赛的时候没想出做法,现在补上。



题解:

  我们考虑,当lowbit(A xor B) = 2p时,A和B表示的二进制数的后p-1位肯定相同。于是我们可以维护一棵字典树,对于每个数x,可以将其转换为30位的二进制数(不足30位的在前面补0),将该二进制数逆序后插入字典树。统计答案时,对于Ai我们先将其同上述做法转换为30位的二进制数,然后逆序后在字典树中查找,对于路径上的每个结点x,如果它下一步对应的边是v,则和它xor后lowbit为2k的数有cnt(x , !v)个。cnt(x , v)表示x的对应的v这条边的子树个数。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
const int maxn = 50000 + 10;
const int MOD = 998244353;
const int sigma_size = 2;
struct Trie {
    int ch[maxn * 30][sigma_size];
    LL cnt[maxn * 30] , pow[35];
    int size;
    void init() {
        size = pow[0] = 1;
        memset(ch[0] , 0 , sizeof(ch[0]));
        memset(cnt , 0 , sizeof(cnt));
        for(int i = 1 ; i < 33 ; i++)
            pow[i] = pow[i - 1] << 1;
    }
    int index(char c)    {    return c - ‘0‘;    }
    void insert(char *s) {
        int i , rt;
        for(i = rt = 0 ; s[i] != ‘\0‘ ; i++) {
            int c= index(s[i]);
            if(!ch[rt][c]) {
                memset(ch[size] , 0 , sizeof(ch[size]));
                ch[rt][c] = size++;
            }
            rt = ch[rt][c];
            cnt[rt] = (cnt[rt] + 1) % MOD;
        }
    }
    LL find(char *s) {
        int i , rt;
        LL ret;
        for(i = rt = ret = 0 ; s[i] != ‘\0‘ ; i++) {
            int c = index(s[i]);
            if(ch[rt][!c]) {
                int tmp = ch[rt][!c];
                ret = (ret + (pow[i] * (1LL * cnt[tmp]))) % MOD;
            }
            rt = ch[rt][c];
        }
        return ret;
    }
} trie;
void binary(int x , char *s)
{
    int i = 0;
    while(x) {
        s[i++] = x % 2 + ‘0‘;
        x >>= 1;
    }
    while(i < 31)    s[i++] = ‘0‘;
    s[i] = ‘\0‘;
}
int a[maxn];    char s[100];

int main()
{
    int n , T;
    cin >> T;
    for(int cas = 1 ; cas <= T ; cas++)
    {
        trie.init();
        scanf("%d" , &n);
        for(int i = 1 ; i <= n ; i++) {
            scanf("%d" , &a[i]);
            binary(a[i] , s);
            trie.insert(s);
        }
        LL ans = 0;
        for(int i = 1 ; i <= n ; i++) {
            binary(a[i] , s);
            ans = (ans + trie.find(s)) % MOD;
        }
        printf("Case #%d: %I64d\n" , cas , ans);
    }
    return 0;
}
时间: 2024-08-05 08:11:34

HDU5269 字典树的相关文章

hdu5269 ZYB loves Xor I 异或,字典树

hdu5269  ZYB loves Xor I   异或,字典树 ZYB loves Xor I Accepts: 142 Submissions: 696 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 ZYB喜欢研究Xor,现在他得到了一个长度为nn的数组A.于是他想知道:对于所有数对(i,j)(i \in [1,n],j \in [1,n])(i,j)(i∈[1,n

hdu 1251 统计难题(字典树)

Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串. 注意:本题只有一组测试数据,处理到文件结束. Output 对于每个提

51nod round3# 序列分解(折半枚举+字典树)

小刀和大刀是双胞胎兄弟.今天他们玩一个有意思的游戏. 大刀给小刀准备了一个长度为n的整数序列.小刀试着把这个序列分解成两个长度为n/2的子序列. 这两个子序列必须满足以下两个条件: 1.他们不能相互重叠. 2.他们要完全一样. 如果小刀可以分解成功,大刀会给小刀一些糖果. 然而这个问题对于小刀来说太难了.他想请你来帮忙. Input 第一行给出一个T,表示T组数据.(1<=T<=5) 接下来每一组数据,输入共2行. 第一行包含一个整数n (2<=n<=40且为偶数). 第二行给出n

白话算法与数据结构之【字典树】

1. 什么是trie树 1.Trie树 (特例结构树) Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高.      Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子

[算法系列之二十]字典树(Trie)

一 概述 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 二 优点 利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高. 三 性质 (1)根节点不包含字符,除根节点外每一个节点都只包含一个字符: (2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串: (3)每个节点的所有子节点包含的字符都不相同. 单词列表为"apps&

poj 3764 The xor-longest Path(字典树)

题目链接:poj 3764 The xor-longest Path 题目大意:给定一棵树,每条边上有一个权值,找出一条路径,使得路径上权值的亦或和最大. 解题思路:dfs一遍,预处理出每个节点到根节点路径的亦或和rec,那么任意路径均可以表示rec[a] ^ rec[b],所以问题 就转换成在一些数中选出两个数亦或和最大,那么就建立字典树查询即可. #include <cstdio> #include <cstring> #include <algorithm> us

字典树

字典树(Trie)是一种很特别的树状信息检索数据结构,如同其名,它的构成就像一本字典,可以让你快速的进行字符插入.字符串搜索等. Trie 一词来自 retrieval,发音为 /tri:/ "tree",也有人读为 /tra?/ "try". 字典树设计的核心思想是空间换时间,所以数据结构本身比较消耗空间.但它利用了字符串的共同前缀(Common Prefix)作为存储依据,以此来节省存储空间,并加速搜索时间.Trie 的字符串搜索时间复杂度为 O(m),m 为最

字典树的简单实现

Trie树,又称为字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树数据结构. 用于保存大量的字符串.它的优点是:利用字符串的公共前缀来节约存储空间. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. 它有3个基本性质: 1.根节点不包含字符,除根节点外每一个节点都只包含一个字符. 2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串. 3.每个节点的所有子节点包含的字符都不相同. 搜索字典项目的方法为: (1)

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类