题目链接: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; }