hdu 5269 ZYB loves Xor I(字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5269

思路分析:当lowbit(AxorB)=2p 时,表示A与B的二进制表示的0-p-1位相等,第p位不同;考虑维护一棵字母树,将所有数字

转换为二进制形式并且从第0位开始插入树中,并在每个节点中记录通过该结点的数字数目;最后统计答案,对于每一个数字,

对于在其路径中的每一个结点X,假设其为第K层,统计通过与该结点不同的值的结点的数目count,则结果增加count*2k;

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int MAX_N = 5 * 10000 + 100;
int num[MAX_N];
struct Node{
    Node *child[2];
    int count;
    Node(){
        count = 0;
        memset(child, 0, sizeof(child));
    }
    Node(int value){
        count = value;
        memset(child, 0, sizeof(child));
    }
};

void Insert(Node *head, int value){
    Node *pre = head, *next = NULL;
    for (int i = 0; i < 30; ++ i){
        if (pre->child[value & 1] == NULL){
            pre->child[value & 1] = new Node(1);
            pre = pre->child[value & 1];
        }else{
            next = pre->child[value & 1];
            next->count++;
            pre = next;
        }
        value >>= 1;
    }
}

void MakeEmpty(Node *node){
    node->count = 0;
    if (node->child[0])
        MakeEmpty(node->child[0]);
    if (node->child[1])
        MakeEmpty(node->child[1]);
}

long long Query(Node *head, int value){
    Node *pre = head, *next = NULL, *other;
    long long ret = 0;

    for (int i = 0; i < 30; ++ i){
        next = pre->child[value & 1];
        other = pre->child[(value & 1) ^ 1];
        if (other)
            ret = (ret + other->count * (1 << i)) % 998244353;
        pre = next;
        value >>= 1;
    }
    return ret;
}

int main(){
    int case_times, n;
    int case_id = 0;

    scanf("%d", &case_times);
    while (case_times--){
        Node *head = new Node();

        scanf("%d", &n);
        for (int i = 0; i < n; ++i){
            scanf("%d", &num[i]);
            Insert(head, num[i]);
        }

        long long ans = 0;
        for (int i = 0; i < n; ++i)
            ans = (ans + Query(head, num[i])) % 998244353;
        MakeEmpty(head);
        printf("Case #%d: %I64d\n", ++case_id, ans);
    }
    return 0;
}
时间: 2024-12-13 05:10:03

hdu 5269 ZYB loves Xor I(字典树)的相关文章

hdu 5269 ZYB loves Xor I

今晚best code第二题 好好学了下字典树,确实自己会的东西实在太少了 #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> #include<queue> #include<map> #include<stack> #include<list> #include<

HDU 5269 ZYB loves Xor I( 01 Trie 树)

题目链接:传送门 题意: 求 for i: 1~n  forj:1~n lowbit(a[i]^a[j]) lowbit(x)表示取x的最低位1. lowbit(3)=1    lowbit(6)=2; 分析: 因为其中有一个异或运算,我们就先来分析这个异或运算.发现如果lowbit(x^y) = 2^p; 那么把x^y转化成2进制后他们的前p-1位一定是相同的.那么思路就来了把所有的数字转换 成01字符串,注意要使他们的长度都相等,然后建一颗trie树.然后遍历的时候如果同时 有左右孩子的话那

hdu 5269 ZYB loves Xor I(计数

题意:给出n个数,n个数两两异或后的最后一个bit位k,求所有2^k的和. 比赛的时候递归写挂了....痛心啊...后来看了半天结果把一个数组移到函数体里就1a了(递归的时候覆盖了...)T_T. 思路是这样的:如果最后一位不相同,那么他们异或结果的最后一位与二者最后一位较低的相同,那么把这些数字按最后一位的位置分为若干组,然后不同组可以直接相乘.相同组因为最后一位相同,所以异或的结果与最后一位无关,把最后一位去掉然后递归处理这一组.因为一共有30位,数组长度为n,复杂度大概是O(30*n).

【HDU】5269 ZYB loves Xor I

[算法]trie [题解] 为了让数据有序,求lowbit无法直接排序,从而考虑倒过来排序,然后数据就会呈现出明显的规律: 法一:将数字倒着贴在字典树上,则容易发现两数的lowbit就是它们岔道结点的深度,所以先建树后对于一个数字依次把每次分岔开的另一边的size乘上权值累加答案. 法二:从高位到低位分组求和,即第一位1在上,0在下,则两边之间互相计算过后就再无影响,只剩下各自内部的事情再处理.由于排序后数据的有序性使分治可行. 法三:排序后对于一个数字,它和后面的数字的lowbit有单调性--

bestcoder r44 p3 hdu 5270 ZYB loves Xor II

这是昨晚队友跟我说的题,不知道当时是什么玄幻的事件发生了,,我看成了两两相乘的XOR 纠结了好长时间间 不知道该怎么办 今天早上看了下这道题,发现是两两相加的XOR  然后就想了想昨晚的思路 发现可做 对于 XOR 在我的记忆中 ,大部分的都是拆成数位来做 那么这题  .... 其实也是类似的 拆成数位.有两种拆法  将数据拆成数位和将答案拆成数位(其实就是考虑答案的每一位) 想了想将数据拆成数位·········· 没法单独考虑每一位的‘功’ 那就将考虑答案的每一位了 最好考虑的是第一位了 只

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 4825 Xor Sum 字典树+位运算

点击打开链接 Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 291    Accepted Submission(s): 151 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus

HDU 1247 Hat&#39;s Words (字典树)

[题目链接]click here~~ [题目大意]A hat's word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary. ,找出由两个子字符串组成的字符串. [解题思路]字典树 #include <bits/stdc++.h> using namespace std; const int N=5*1e4+100; const int MOD=

hdu 1247:Hat’s Words(字典树,经典题)

Hat's Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7282    Accepted Submission(s): 2639 Problem Description A hat's word is a word in the dictionary that is the concatenation of exactly