[洛谷P3674]小清新人渣的本愿
题目大意:给你$n$个数,$m$个询问($n,m\leqslant 10^5$),有三种
- $1\;l\;r\;x$询问区间$[l,r]$内有没有两个数相减等于$x$
- $2\;l\;r\;x$询问区间$[l,r]$内有没有两个数相加等于$x$
- $3\;l\;r\;x$询问区间$[l,r]$内有没有两个数相乘等于$x$
注意,两个数位置可以相同
题解:莫队。
- 1. 即询问区间有没有一个数$s_i$,存在$s_i+x$
- 即询问区间有没有一个数$s_i$,存在$x-s_i$。$-s_i$不好考虑?存一个$N-s_i$不就好了?($N$为一个很大的数)
- 即询问区间有没有一个数$s_i|x$,存在$\dfrac{x}{s_i}$
这复杂度是$O(m(\sqrt{n}+C))$($C=\max\{\max\{x_i\},\max\{s_i\}\}$,题目中给的是$C\leqslant 10^5$)
过不了?
注意到操作一,好像像一个偏移,可以用$bitset$。
那么操作二呢?
$-s_i$不好考虑?存一个$N-s_i$不就好了?($N$为一个很大的数),也可以偏移耶。
操作三?
这个没有什么很好的方法,暴力枚举它的约数$s_i$,看是否存在$\dfrac{n}{s_i}$,反正时间复杂度为$O(\sqrt{x})$
所以总复杂度为$O(m(\sqrt{n}+\dfrac{C}{64}))$
卡点:无
C++ Code:
#include <cstdio>
#include <algorithm>
#include <bitset>
#include <cmath>
#define bsz 317
#define maxn 100010
const int N = (1 << 17) - 1;
std::bitset<N + 1> a, b, ans;
int n, m;
int s[maxn], cnt[maxn];
struct node {
int op, l, r, x, num;
inline bool operator < (const node &rhs) const {return (l / bsz == rhs.l / bsz) ? ((l / bsz + 1 & 1) ? (r < rhs.r) :(r > rhs.r)) : l < rhs.l;}
} q[maxn];
void work(int op, int x, int tg) {
if (op == 1) ans[tg] = (a & a >> x).any();
if (op == 2) ans[tg] = (a & b >> N - x).any();
if (op == 3) for (int i = sqrt(x); i; i--) if ((x % i == 0) && a[i] && a[x / i]) {ans.set(tg); break;}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &s[i]);
for (int i = 1; i <= m; i++) scanf("%d%d%d%d", &q[i].op, &q[i].l, &q[i].r, &q[i].x), q[i].num = i;
std::sort(q + 1, q + m + 1);
int l = 1, r = 1;
cnt[s[1]]++, a[s[1]] = b[N - s[1]] = true;
for (int i = 1; i <= m; i++) {
while (l > q[i].l) cnt[s[--l]]++ ? 0 : a[s[l]] = b[N - s[l]] = true;
while (r < q[i].r) cnt[s[++r]]++ ? 0 : a[s[r]] = b[N - s[r]] = true;
while (l < q[i].l) --cnt[s[l++]] ? 0 : a[s[l - 1]] = b[N - s[l - 1]] = false;
while (r > q[i].r) --cnt[s[r--]] ? 0 : a[s[r + 1]] = b[N - s[r + 1]] = false;
work(q[i].op, q[i].x, q[i].num);
}
for (int i = 1; i <= m; i++) puts(ans[i] ? "hana" : "bi");
return 0;
}

浙公网安备 33010602011771号