Loading

异或粽子 题解

题目链接

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

选两个整数数 l,r
满足 1lrn
将编号在 [l,r] 范围内的所有馅儿混合做成一个粽子。
所得的粽子的美味度为这些粽子的属性值的异或和。

看到有关异或和的问题,首先想到对于 ai 做一次异或前缀和。
形如这样:xors[i] = xors[i - 1] ^ a[i];
这样的话我们可以用 O(n2) 的方法把每一种的价值 O(1) 算出来。
然后把这 n2 个值 std::sort 一下,那么答案是:

i=1kxorsi

所以 60 pts 就得到了。(真心认为是送分)

接下来我们来看正解的做法:

看到异或最大值,直接想到构建一个 Trie 树。
每一次求最大值时优先走和当前位不一样的节点,结合二进制即可发现得出结果最大。

但是这题是求最大的 k 个异或的值。
我们还是先建出 Trie 树,然后定义 query(x,y) 表示:

对于数字 xx 异或和第 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 @   Aonynation  阅读(128)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示