【题解】P5355 [Ynoi2017] 由乃的玉米田

时间:2022-01-24
本文章向大家介绍【题解】P5355 [Ynoi2017] 由乃的玉米田,主要包括【题解】P5355 [Ynoi2017] 由乃的玉米田使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意

P4688 [Ynoi2016] 掉进兔子洞

给定一个长为 \(n\) 的序列和 \(m\) 个操作,每次操作询问区间 \([l, r]\) 内是否可以选出两个数 \(a_x, a_y\),使得:

  1. \(a_x - a_y = x\)

  2. \(a_x + a_y = x\)

  3. \(a_x \cdot a_y = x\)

  4. \(\min(a_x, a_y) \mid \max(a_x, a_y)\)\(\frac{\max(a_x, a_y)}{\min(a_x, a_y)} = x\)

\(n, m \leq 10^5, 0 \leq x \leq 10^5, 1 \leq a_i \leq 10^5\)

思路

莫队 + bitset + 根号分治。

bitset 的基本用法

P3674 小清新人渣的本愿 的强化版。

不用修改,不强制在线,考虑 莫队 处理。

不妨令 \(N\) 为某一极大值,同时维护两个 bitset \(s1, s2\),其中 \(s1\) 表示值 \(x\) 是否在当前区间内出现过,\(s2\) 表示值 \(N - x\) 是否在当前区间内出现过。

对于操作 \(1\),如果 \([l, r]\) 内存在 \(a - b = x\),因为 \(b\) 可以表示成 \(a - x\),所以 \([l, r]\) 内也一定存在 \(a, a - x\),则问题转化成:是否可以在 \([l, r]\) 内选出 \(a\) 使得 \([l, r]\) 内同时存在 \(a, a - x\),可以用 s1[a] == s1[a - x] == true 判断。不难发现上面的代码等价于 (s1 & (s1 << x)).any()

对于操作 \(2\),回顾 \(s2\) 的定义,发现 (s2 >> (N - x))[i] 实际上维护的是 \([l, r]\) 内是否存在 \((N - i) - (N - x) = x - i\)。故而我们可以用 (s1 & (s2 >> (N - x))).any() 判断 \([l, r]\) 内是否存在 \(a + b = x\)。由于 bitset 不能维护负数下标,\(N\) 应该取到 \(10^5\) 及以上。

对于操作 \(3\),因为 \(0 \leq x \leq 10^5\),所以可以暴力枚举 \(x\) 的因数并用 \(s1\) 判断。

对于操作 \(4\),发现难以直接用莫队维护。令 \([l, r]\) 中的最大值为 \(k\),因为当 \(x \geq \sqrt{k}\) 时,暴力枚举商为 \(x\) 的两个数复杂度是 \(\mathcal{O}(\sqrt{n})\),所以可以考虑 根号分治

\(x \geq \sqrt{k}\) 时,暴力枚举商为 \(x\) 的两个数即可。

\(x < \sqrt{k}\) 时,考虑 \(\mathcal{O}(n\sqrt{n})\) 预处理答案。令 \(a_i\) 的最大值为 \(K\),不妨对于 \(1 \leq x < \sqrt{K}\) 预处理 \(p_i\)\(p_i = l\) 表示 \([l, i]\) 内存在 \(\frac{a}{b} = x\)\(i - l\) 最小。对于询问 \([l, r]\) 内是否存在 \(\frac{a}{b} = x\),显然若 \(l \leq p_r\) 则存在,反之则不存在。

莫队部分时间复杂度 \(\mathcal{O}(n \sqrt{n})\),根号分治时间复杂度 \(\mathcal{O}(n \sqrt{n})\),因此总时间复杂度 \(\mathcal{O}(n \sqrt{n})\)

代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;

#define rint register int

inline int read(){
    rint x=0,c=getchar();
    for(;c<48||c>57;c=getchar());
    for(;c>47&&c<58;c=getchar())x=x*10+(c^48);
    return x;
}

const int maxn = 1e5 + 5;

int n, m;
int maxv, len;
int lst[maxn], pre[maxn];
int a[maxn], bel[maxn], cnt[maxn];
bool ans[maxn];
bitset<maxn> s1, s2;

struct node {
	int l, r, x, opt, id;
	
	node(): l(), r(), x(), opt(), id() {}
	
	node(int _l, int _r, int _x, int _opt, int _id): l(_l), r(_r), x(_x), opt(_opt), id(_id) {}
	
	bool operator < (const node& rhs) const {
		if (bel[l] ^ bel[rhs.l]) {
			return bel[l] < bel[rhs.l];
		}
		return (bel[l] & 1 ? r < rhs.r : r > rhs.r);
	}
} q1[maxn];

vector<node> q2[maxn];

inline void add(rint x) {
	cnt[a[x]]++;
	if (cnt[a[x]] == 1) {
		s1[a[x]] = true;
		s2[maxv - a[x]] = true;
	}
}

inline void del(rint x) {
	cnt[a[x]]--;
	if (!cnt[a[x]]) {
		s1[a[x]] = false;
		s2[maxv - a[x]] = false;
	}
}

int main() {
	rint opt, l, r, x, tmp;
	rint left = 0, right = 0;
	n = read(), m = read();
	rint block = sqrt(n);
	for (rint i = 1; i <= n; i++) {
		a[i] = read();
		maxv = max(maxv, a[i] + 1);
		bel[i] = (i - 1) / block + 1;
	}
	block = sqrt(maxv);
	for (rint i = 1; i <= m; i++) {
		opt = read(), l = read(), r = read(), x = read();
		if ((opt == 4) && (x < block)) {
			q2[x].push_back(node(l, r, x, opt, i));
		} else {
			len++;
			q1[len] = node(l, r, x, opt, i);
		}
	}
	sort(q1 + 1, q1 + len + 1);
	for (rint i = 1; i <= len; i++) {
		while (left > q1[i].l) {
			add(--left);
		}
		while (right < q1[i].r) {
			add(++right);
		}
		while (left < q1[i].l) {
			del(left++);
		}
		while (right > q1[i].r) {
			del(right--);
		}
		if (q1[i].opt == 1) {
			ans[q1[i].id] = (s1 & (s1 << q1[i].x)).any();
		} else if (q1[i].opt == 2) {
			ans[q1[i].id] = (s1 & (s2 >> (maxv - q1[i].x))).any();
		} else if (q1[i].opt == 3) {
			for (rint j = 1; j * j <= q1[i].x; j++) {
				if (q1[i].x % j == 0) {
					if (s1[j] && s1[q1[i].x / j]) {
						ans[q1[i].id] = true;
						break;
					}
				}
			}
		} else {
			for (rint j = 1; q1[i].x * j <= maxv; j++) {
				if (s1[j] && s1[q1[i].x * j]) {
					ans[q1[i].id] = true;
					break;
				}
			}
		}
	}
	for (rint i = 1; i < block; i++) {
		if (!q2[i].size()) {
			continue;
		}
		memset(lst, 0, (maxv + 1) * sizeof(int));
		memset(pre, 0, (n + 1) * sizeof(int));
		for (rint j = 1; j <= n; j++) {
			pre[j] = pre[j - 1];
			lst[a[j]] = j;
			tmp = a[j] * i;
			if (tmp <= maxv) {
				pre[j] = max(pre[j], lst[tmp]);
			}
			tmp = a[j] / i;
			if (a[j] % i == 0) {
				pre[j] = max(pre[j], lst[tmp]);
			}
		}
		for (rint j = 0; j < q2[i].size(); j++) {
			ans[q2[i][j].id] = (q2[i][j].l <= pre[q2[i][j].r]);
		}
	}
	for (rint i = 1; i <= m; i++) {
		putchar('y'), putchar('u');
		if (ans[i]) {
			putchar('n'), putchar('o');
		} else {
			putchar('m'), putchar('i');
		}
		putchar('\n');
	}
	return 0;
}

原文地址:https://www.cnblogs.com/lingspace/p/p5355.html