题目大意:给你$n$个数,$m$个询问($n,mleqslant 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}}$,题目中给的是$Cleqslant 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; }