ZROI P2592 题解
2023年8月5日
ZROI P2592 题解
题面
点击此处展开题面
找众数战士
给定一个长度为 的序列,你需要对于每个前缀,找到出现次数最多的那个数字。如果有多个出现次数最多的数字,输出最小的那个。
由于输出的数字太多了,为了加快输出,你只需要输出所有数字的异或和。
输入格式
第一行一个正整数 。
第二行 个正整数 ,表示序列。
由于输入量较大,建议使用快速输入。
输出格式
一个非负整数,表示输出数字的异或和。
样例
输入:
7
1 3 2 2 1 2 1输出:
1数据范围
对于 100% 的数据,。
- 测试点 1~3:
- 测试点 4~7:
- 测试点 8~10:
提示
(原题在这里给了个快读板子)
解题
记 为前 个数中出现最多的数字。
根据加上第 个数后的情况分类讨论:
- 加上第 个数后, 不是前 个数中出现最多的数字
- 加上第 个数后, 是前 个数中出现最多的数字
对于情况 1,有 。
对于情况 2,有 。
如何判断 是不是出现最多的那个呢?
建一个桶 , 代表到 出现过(包括当前计算到的)的次数。本题 ,空间 1 GB,开得下。
对于第 个数,记当前数字出现的次数 为 ,记上一个数字出现的次数 为 :如果 ,那么对应情况 1。如果 ,那么对应情况 2。
发现漏掉了 的情况。题中说有多个时取值最小的那个,也就是:如果 ,那么对应情况 1,否则对应情况 2。
发现 与 中除了 以外的元素都无关,所以只需要 和 滚动即可。
代码
#include <iostream>
using namespace std;
/**
 * 快读。
 * @see http://zhengruioi.com/problem/2605
 */
namespace IO {
const int N = 1e7 + 5;
char _READ_[N], _PRINT_[N];
int _READ_POS_, _PRINT_POS_, _READ_LEN_;
inline char readc() {
#ifndef ONLINE_JUDGE
  return getchar();
#endif
  if (!_READ_POS_) {
    if (feof(stdin)) return -1;
    _READ_LEN_ = fread(_READ_, 1, N, stdin);
  }
  char c = _READ_[_READ_POS_++];
  if (_READ_POS_ == _READ_LEN_) _READ_POS_ = 0;
  return c;
}
template <typename T>
inline int read(T &x) {  // NOLINT
  x = 0;
  int flag = 1, c;
  while (((c = readc()) < '0' || c > '9') && c != '-')
    if (c < 0) return -1;
  if (c == '-')
    flag = -1;
  else
    x = c - '0';  // NOLINT
  while ((c = readc()) >= '0' && c <= '9') x = x * 10 - '0' + c;
  x *= flag;
  return 0;
}
}  // namespace IO
const int N = 1e7 + 5;
int count[N], n;
int main() {
  IO::read(n);
  int ans = 0;   // 异或和
  int last = 0;  // 上一个答案
  for (int i = 1; i <= n; ++i) {
    int a;
    IO::read(a);
    ++count[a];
    if (count[a] > count[last])
      last = a;  // 当前数字的出现次数更多
    else if (count[a] == count[last] && a < last)
      last = a;  // 一样多,但更小
    ans ^= last;
  }
  printf("%d", ans);
  return 0;
}