题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536
题目大意是给了一个序列,求(si+sj)^sk的最大值。
首先n有1000,暴力理论上是不行的。
此外题目中说大数据只有10组,小数据最多n只有100。(那么c*n^2的复杂度应该差不多)
于是可以考虑枚举i和j,然后匹配k。
于是可以先把所有s[k]全部存进一个字典树,
然后枚举s[i]和s[j],由于i、j、k互不相等,于是先从字典树里面删掉s[i]和s[j],然后对s[i]+s[j]这个数在字典树中匹配,自然是高位如果能xor出1就匹配,不能就0。这个和普通的xor两个匹配最值是一样的。
匹配完,再把s[i]和s[j]加回去。
复杂度O(15n*n)左右.
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <set> #include <queue> #include <vector> #define LL long long using namespace std; //求n个数中取出两个数能xor的最大值 //Trie Tree字典树 //len*n, len为数的二进制最大长度 const int maxN = 1005; const int len = 31;//len表示数的二进制最大长度 struct Trie { int next[2]; }tree[maxN*len]; int num[maxN*len]; int cnt, n, a[maxN]; void initTree() { cnt = 0; memset(tree, -1, sizeof(tree)); memset(num, 0, sizeof(num)); } void add(int x) { int now = 0; bool k; for (int i = len; i >= 0; i--) { k = x&(1<<i); if (tree[now].next[k] == -1) tree[now].next[k] = ++cnt; now = tree[now].next[k]; num[now]++; } } void del(int x) { int now = 0; bool k; for (int i = len; i >= 0; i--) { k = x&(1<<i); now = tree[now].next[k]; num[now]--; } } //返回当前数中能和x合成最大数的数 int query(int x) { int v = 0, now = 0; bool k; for (int i = len; i >= 0; i--) { k = x&(1<<i); if (tree[now].next[!k] != -1 && num[tree[now].next[!k]] != 0) k = !k; v = v|(k<<i); now = tree[now].next[k]; } return v; } void input() { initTree(); scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); add(a[i]); } } int myMax(int x, int y) { if (x == -1) return y; else return max(x, y); } void work() { int ans = -1, tmp; for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { del(a[i]); del(a[j]); tmp = a[i]+a[j]; //cout << "****" << tmp << " " << query(tmp) << endl; ans = myMax(ans, tmp^query(tmp)); add(a[i]); add(a[j]); } } printf("%d\n", ans); } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for (int times = 0; times < T; ++times) { input(); work(); } return 0; }
时间: 2024-10-12 12:18:18