标签:
题目链接: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; }
标签:
原文地址:http://www.cnblogs.com/H-Vking/p/4589408.html