字典树 - 求异或的值最大
Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么?
Input输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。Output对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。Sample Input
2 3 2 3 4 5 1 5 4 1 4 6 5 6 3
Sample Output
Case #1: 4 3 Case #2: 4
题目分析 : 给你一堆数,一些询问,问当前输入的数同上面的哪个数异或值最大
思路分析 : 对于当前输入的 n ,我们很容易判断出其与哪个数异或的值最大,当然这个数不一定出现在上来的一堆数中,在这里字典树搞一下就很方便了
不是很懂的地方就是字典树用数组写内存应该开多大的。
代码示例 :
#define ll long long const int maxn = 1e5+5; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; int pre[maxn][40]; int arr[maxn]; int len; int tree[maxn*100][2]; int ans[50]; void init(){ ans[0] = 1; for(int i = 1; i <= 32; i++) ans[i] = ans[i-1]*2; } void fun(int x){ queue<int>que; int f = arr[x]; while(f){ que.push(f%2); f /= 2; } int k = len; while(!que.empty()){ pre[x][k--] = que.front(); que.pop(); } } int rt = 1; void build(int x){ int u = 0, v; for(int i = 1; i <= len; i++){ v = pre[x][i]; if (!tree[u][v]) tree[u][v] = rt++; u = tree[u][v]; } } int pp[50]; int an; void query(){ int u = 0, v; an = 0; for(int i = 1; i <= len; i++){ v = pp[i]; //if (!tree[u][v]) {printf("*****\n"); v ^= 1; u = tree[u][v]; an += (v)*ans[len-i]; } //else {printf("&&&&&&&&&& \n"); u = tree[u][v]; an += v*ans[len-i];} if (!tree[u][v]) v ^= 1; u = tree[u][v]; an += v*ans[len-i]; //printf("an = %d v = %d \n", an, v); } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int t, x; int kase = 1; cin >> t; init(); while(t--){ int n, m; cin >> n >> m; int ma = 0; for(int i = 1; i <= n; i++){ scanf("%d", &arr[i]); ma = max(ma, arr[i]); } len = floor(log(ma)/log(2))+1; //printf("len = %d\n", len); memset(pre, 0, sizeof(pre)); memset(tree, 0, sizeof(tree)); rt = 1; for(int i = 1; i <= n; i++){ fun(i); build(i); //printf("rt = %d\n", rt); } //for(int i = 1; i <= n; i++){ //for(int j = 1; j <= len; j++){ //printf("%d", pre[i][j]); //} //printf("\n"); //} printf("Case #%d:\n", kase++); while(m--){ scanf("%d", &x); memset(pp, 0, sizeof(pp)); int lenth = floor(log(x)/log(2)) + 1; queue<int>que; int f = x; while(f) { que.push(f%2); f /= 2; } if (lenth >= len){ for(int i = len; i >= 1; i--){pp[i] = que.front(); que.pop();} } else { for(int i = len; i >= len-lenth+1; i--) {pp[i]=que.front(); que.pop();} } for(int i = 1; i <= len; i++) pp[i] ^= 1; //for(int i = 1; i <= len; i++) printf("%d ", pp[i]); //printf("\n"); query(); printf("%d\n", an); } } return 0; }
东北日出西边雨 道是无情却有情