2021ICPC江西省赛 Magic Number Group (普通莫队/回滚莫队 维护区间众数)

题目链接: 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;
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值