Loading

异或粽子 题解

题目链接

首先看到题目中定义的每一个粽子的价值:

选两个整数数 \(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;
}
}
*/
posted @ 2022-04-26 21:26  Aonynation  阅读(121)  评论(0编辑  收藏  举报