异或粽子 题解
首先看到题目中定义的每一个粽子的价值:
选两个整数数 \(l, r\) 。
满足 \(1 \leqslant l \leqslant r \leqslant n\) 。
将编号在 \([l, r]\) 范围内的所有馅儿混合做成一个粽子。
所得的粽子的美味度为这些粽子的属性值的异或和。
看到有关异或和的问题,首先想到对于 \(a_i\) 做一次异或前缀和。
形如这样:xors[i] = xors[i - 1] ^ a[i];
。
这样的话我们可以用 \(O(n^2)\) 的方法把每一种的价值 \(O(1)\) 算出来。
然后把这 \(n^2\) 个值 \(\text{std::sort}\) 一下,那么答案是:
\[\sum_{i = 1}^k \text{xors}_i
\]
所以 \(\text{60 pts}\) 就得到了。(真心认为是送分)
接下来我们来看正解的做法:
看到异或最大值,直接想到构建一个 \(Trie\) 树。
每一次求最大值时优先走和当前位不一样的节点,结合二进制即可发现得出结果最大。
但是这题是求最大的 \(k\) 个异或的值。
我们还是先建出 \(Trie\) 树,然后定义 \(\text{query(x,y)}\) 表示:
对于数字 \(x\) 和 \(x\) 异或和第 \(y\) 大的结果是什么。
具体统计的话也很简单。
分两种情况进行比较简单的讨论即可。(参照 二叉查找树)
只关心当前的数字个数是否够用,具体可看代码。
Code
#include <bits/stdc++.h>
#define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define quad putchar(' ')
#define Enter putchar('\n')
namespace FastIO {
template <class T> void read(T &a) {
T s = 0, t = 1;
char c = getchar();
while ((c < '0' || c > '9') && c != '-')
c = getchar();
if (c == '-')
c = getchar(), t = -1;
while (c >= '0' && c <= '9')
s = (s << 1) + (s <<3) + (c ^ 48), c = getchar();
a = s * t;
}
}
#define int long long
const int N = 500005;
int n, k, a[N], xors[N], d[N];
int dis[N * 35][2], pnum, root = 0, siz[N * 35];
struct Node {
int pos, val;
Node (int _pos = 0, int _num = 0) {
pos = _pos;
val = _num;
}
friend bool operator<(const Node &p, const Node &q) {
return p.val < q.val;
}
};
std::priority_queue <Node> que;
namespace Trie {
inline void insert(int num);
inline int query(int num, int Siz);
}
signed main(void) {
// file("P5283");
std::cin >> n >> k;
for (int i = 1; i <= n; i++)
FastIO::read(a[i]);
for (int i = 1; i <= n; i++)
xors[i] = xors[i - 1] ^ a[i];
Trie::insert(0);
for (int i = 1; i <= n; i++)
Trie::insert(xors[i]);
for (int i = 0; i <= n; i++)
d[i] = 1;
for (int i = 0; i <= n; i++)
que.push(Node(i, Trie::query(xors[i], d[i])));
k *= 2;
int ans = 0;
for (int i = 1; i <= k; i++) {
ans += que.top().val;
int now = que.top().pos;
que.pop();
que.push(Node(now, Trie::query(xors[now], ++d[now])));
}
std::cout << ans / 2 << std::endl;
}
namespace Trie {
inline void insert(int num) {
int now = 0;
for (int i = 31; i >= 0; i--) {
int p = num & (1ll << i);
p = (p != 0);
if (dis[now][p])
now = dis[now][p];
else {
pnum++;
dis[now][p] = pnum;
now = dis[now][p];
}
siz[now] ++;
}
}
inline int query(int num, int Siz) {
int now = 0, ret = 0;
for (int i = 31; i >= 0; i--) {
int p = num & (1ll << i);
p = (p != 0);
if (siz[dis[now][1 - p]] < Siz) {
Siz -= siz[dis[now][1 - p]];
now = dis[now][p];
}
else {
ret += (1ll << i);
now = dis[now][1 - p];
}
}
return ret;
}
}
*/