题目链接: Magic Number Group
大致题意
给定一个长度为 n n n的序列, 有 m m m次询问.
每次询问 [ l , r ] [l, r] [l,r]中, 有相同公共质因子的最大数量.
解题思路
莫队
考虑到值域范围只有 1 0 6 10^6 106, 因此对于每个数的不同质因子数量最多只有 8 8 8个.
2 × 3 × 5 × 7 × 11 × 13 × 17 > 1 0 6 2 \times 3 \times 5 \times 7 \times 11 \times 13 \times17 > 10^6 2×3×5×7×11×13×17>106
因此我们不妨用莫队维护区间质因子出现的次数, 取最大值即可.
即: 用莫队维护区间众数.
我们可以通过普通莫队 或 回滚莫队来维护. 复杂度在最坏情况下为 O ( 8 m n ) O(8m\sqrt{n}) O(8mn)
➡️同类题目参考博客⬅️
AC代码
普通莫队
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 5E4 + 10, M = 1E6 + 10, B = 225;
struct mo {
int l, r, id;
bool operator< (const mo& t) const {
if (l / B != t.l / B) return l < t.l;
return l / B & 1 ? r < t.r : r > t.r;
}
}; vector<mo> area;
vector<int> nums[N];
int cou[M], num[M], qmax;
int res[N];
void add(int pos) {
for (auto& op : nums[pos]) {
cou[num[op]++]--;
cou[num[op]]++;
qmax = max(qmax, num[op]);
}
}
void sub(int pos) {
for (auto& op : nums[pos]) {
cou[num[op]--]--;
cou[num[op]]++;
if (cou[qmax] == 0) qmax--;
}
}
int main()
{
int t; cin >> t;
while (t--) {
area.clear();
int n, m; scanf("%d %d", &n, &m);
rep(i, n) {
nums[i].clear();
int x; scanf("%d", &x);
for (int j = 2; j <= x / j; ++j) {
if (x % j == 0) {
while (x % j == 0) x /= j;
nums[i].push_back(j);
}
}
if (x > 1) nums[i].push_back(x);
}
rep(i, m) {
int l, r; scanf("%d %d", &l, &r);
area.push_back({ l, r, i });
}
sort(area.begin(), area.end());
int L = 1, R = 0;
for (auto& [l, r, id] : area) {
while (l < L) add(--L);
while (r > R) add(++R);
while (L < l) sub(L++);
while (R > r) sub(R--);
res[id] = qmax;
}
rep(i, m) printf("%d\n", res[i]);
while (L <= R) sub(L++); qmax = 0;
}
return 0;
}
回滚莫队
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 5E4 + 10, M = 1E6 + 10, B = 225;
vector<int> nums[N];
struct mo {
int l, r, id;
bool operator< (const mo& t) const {
if (l / B != t.l / B) return l < t.l;
return r < t.r;
}
}; vector<mo> area;
int res[N];
int cou[M], qmax;
void add(int pos) {
for (auto& op : nums[pos]) qmax = max(qmax, ++cou[op]);
}
void clear(int l, int r) {
for (int i = l; i <= r; ++i) {
for (auto& op : nums[i]) cou[op]--;
}
}
void bruth(int l, int r, int id) {
for (int i = l; i <= r; ++i) add(i);
res[id] = qmax;
clear(l, r); qmax = 0;
}
int main()
{
int T; cin >> T;
while (T--) {
area.clear();
int n, m; scanf("%d %d", &n, &m);
rep(i, n) {
nums[i].clear();
int x; scanf("%d", &x);
for (int j = 2; j <= x / j; ++j) {
if (x % j == 0) {
while (x % j == 0) x /= j;
nums[i].push_back(j);
}
}
if (x > 1) nums[i].push_back(x);
}
rep(i, m) {
int l, r; scanf("%d %d", &l, &r);
area.push_back({ l, r, i });
}
sort(area.begin(), area.end());
int L = 1, R = 0, last = -1;
for (auto& [l, r, id] : area) {
if (l / B != last) {
clear(L, R); qmax = 0;
L = (l / B + 1) * B, R = L - 1, last = l / B;
}
if (l / B == r / B) {
bruth(l, r, id);
continue;
}
while (R < r) add(++R);
int bqmax = qmax;
for (int i = l; i <= L - 1; ++i) add(i);
res[id] = qmax;
clear(l, L - 1); qmax = bqmax;
}
rep(i, m) printf("%d\n", res[i]);
clear(L, R);
}
return 0;
}