老夫聊发少年狂,碱金属,丢池塘。浮溶游响,激起千|

Yaosicheng124

园龄:1年2个月粉丝:8关注:11

区间众数问题

简介

一个数列的众数是指其中出现次数最多的数,求解区间众数问题有很多种方法。

方法1

注意,此种方法只用于求解众数出现次数。

使用莫队求解。

可是如何维护呢?

首先进行离散化。

我们定义 cnti 表示数字 i 在当前区间中的出现次数,toti 表示当前区间中出现次数为 i 的数字数量,p 表示当前区间众数的出现次数。

于是,我们就可以这么在扩大区间时维护(设扩大后的端点为 x):

totcntaxtotcntax1cntaxcntax+1totcntaxtotcntax+1p=max(p,cntax)

这么维护缩小(设缩小前的端点为 x):

totcntaxtotcntax1cntaxcntax1totcntaxtotcntax+1p{totcntax=0,p1totcntax0,p

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 200001, S = 448;

struct Node {
  int l, r, id;
}s[MAXN];

int n, q, a[MAXN], b[MAXN], cnt[MAXN], tot[MAXN], ans[MAXN], top;

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> q;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    b[i] = a[i];
  }
  sort(b + 1, b + n + 1);
  for(int i = 1; i <= n; ++i) {
    if(!tot || b[i] > b[top]) {
      b[++top] = b[i];
    }
  }
  for(int i = 1; i <= n; ++i) {
    a[i] = lower_bound(b + 1, b + top + 1, a[i]) - b;
  }
  for(int i = 1; i <= q; ++i) {
    cin >> s[i].l >> s[i].r;
    s[i].id = i;
  }
  sort(s + 1, s + q + 1, [](const Node &a, const Node &b) { return (a.l / S == b.l / S ? (a.l / S % 2 ? a.r > b.r : a.r < b.r) : a.l / S < b.l / S); });
  cnt[a[1]]++, tot[1]++;
  for(int i = 1, x = 1, y = 1, p = 1; i <= q; ++i) {
    for(; x > s[i].l; tot[cnt[a[--x]]++]--, tot[cnt[a[x]]]++, p = max(p, cnt[a[x]])) {
    }
    for(; y < s[i].r; tot[cnt[a[++y]]++]--, tot[cnt[a[y]]]++, p = max(p, cnt[a[y]])) {
    }
    for(; x < s[i].l; tot[cnt[a[x]]]--, (!tot[p] ? p-- : p = p), tot[--cnt[a[x++]]]++) {
    }
    for(; y > s[i].r; tot[cnt[a[y]]]--, (!tot[p] ? p-- : p = p), tot[--cnt[a[y--]]]++) {
    }
    ans[s[i].id] = p;
  }
  for(int i = 1; i <= q; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}

方法2

注意,此类方法只适用于求解绝对众数。

绝对众数是指数列中出现次数 >N2 的数,一个数列的绝对众数至多一个。

这里用的方法是一种玄学的随机化。

因为绝对众数出现次数超过一半,所以我们可以随机出数列中的一个数,每次都有 12 的概率抽到绝对众数,所以我们抽 k 次存在绝对众数但没找到的概率为 12k

现在考虑如何判断一个数是否是绝对众数。方法也很简单:首先进行离散化,将相等的数出现位置放入一个 vector 中,再通过二分求出 lr 有多少个当前数。

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 300005;

int n, q, a[MAXN], b[MAXN], tot;
vector<int> v[MAXN];
mt19937 gen(time(0));

int rnd(int l, int r) {
  uniform_int_distribution<int> Rand(l, r);
  return Rand(gen);
}

int Calc(int l, int r, int x) {
  auto a = lower_bound(v[x].begin(), v[x].end(), l), b = upper_bound(v[x].begin(), v[x].end(), r);
  return b - a;
}

int Find(int l, int r) {
  int x = rnd(l, r), cnt = Calc(l, r, a[x]);
  for(int i = 1; i <= 60 && cnt <= (r - l + 1) / 2; x = rnd(l, r), cnt = Calc(l, r, a[x]), ++i) {
  }
  return (cnt <= (r - l + 1) / 2 ? -1 : b[a[x]]);
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> q;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    b[i] = a[i];
  }
  sort(b + 1, b + n + 1);
  for(int i = 1; i <= n; ++i) {
    if(!tot || b[i] > b[tot]) {
      b[++tot] = b[i];
    }
  }
  for(int i = 1; i <= n; ++i) {
    a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
    v[a[i]].push_back(i);
  }
  for(int i = 1, l, r; i <= q; ++i) {
    cin >> l >> r;
    cout << Find(l, r) << "\n";
  }
  return 0;
}

本文作者:yaosicheng124

本文链接:https://www.cnblogs.com/yaosicheng124/p/18158126

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Yaosicheng124  阅读(201)  评论(0编辑  收藏  举报
  1. 1 Minecraft C418
Minecraft - C418
00:00 / 00:00
An audio error has occurred.

暂无歌词

加载中…

{{tag.name}}

{{tran.text}}{{tran.sub}}
无对应文字
有可能是
{{input}}
尚未录入,我来提交对应文字
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示