区间众数问题
简介
一个数列的众数是指其中出现次数最多的数,求解区间众数问题有很多种方法。
方法1
注意,此种方法只用于求解众数出现次数。
使用莫队求解。
可是如何维护呢?
首先进行离散化。
我们定义
于是,我们就可以这么在扩大区间时维护(设扩大后的端点为
这么维护缩小(设缩小前的端点为
代码
#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
注意,此类方法只适用于求解绝对众数。
绝对众数是指数列中出现次数
这里用的方法是一种玄学的随机化。
因为绝对众数出现次数超过一半,所以我们可以随机出数列中的一个数,每次都有
现在考虑如何判断一个数是否是绝对众数。方法也很简单:首先进行离散化,将相等的数出现位置放入一个 vector
中,再通过二分求出
代码
#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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步