感觉在哪做过的一道题.
Description
给一列数, 每次询问一个区间, 问能不能用这个区间内的两个数(可以是同一个), 相加/相减/相乘出询问的数.
Solution
总觉得是某道题是一样的套路, 小清新系列的一道题.
乘法直接暴力枚举约数.
用bitset维护正负两个的出现情况, 负数的用常量$maxv$减一下, 然后查询的时候加减法就推推式子, 移位以后再与一下, 检查有没有值就行了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <bits/stdc++.h>
using namespace std;
const int maxn = 1e+5 + 5;
int n, m, a[maxn], r[maxn], bel[maxn], mx, ans[maxn]; struct question { int l, r, t, x, id; inline bool operator<(const question &rhs) const { return (bel[l] == bel[rhs.l]) ? r < rhs.r : bel[l] < bel[rhs.l]; } }q[maxn]; bitset<maxn> cur, ruc, upd; int cnt[maxn];
inline int rd() { register int x = 0, c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar(); return x; } inline void add(int x) { if (!cnt[x]) cur[x] = 1, ruc[mx - x] = 1; cnt[x]++; } inline void del(int x) { if (cnt[x] == 1) cur[x] = 0, ruc[mx - x] = 0; cnt[x]--; }
int main() { n = rd(); m = rd(); mx = 100001; for (int i = 1; i <= n; ++i) a[i] = rd(), r[i] = mx - a[i]; int blo = sqrt(n); for (int i = 1; i <= n; ++i) bel[i] = (i - 1) / blo + 1; for (int i = 1; i <= m; ++i) { q[i].t = rd(); q[i].l = rd(); q[i].r = rd(); q[i].x = rd(); q[i].id = i; } sort(q + 1, q + 1 + m); int L = 1, R = 0; for (int i = 1; i <= m; ++i) { while (L > q[i].l) add(a[--L]); while (R < q[i].r) add(a[++R]); while (L < q[i].l) del(a[L++]); while (R > q[i].r) del(a[R--]); if (q[i].t == 1) { upd = ((cur >> q[i].x) & cur); ans[q[i].id] = upd.count(); } else if (q[i].t == 2) { upd = ((ruc >> (mx - q[i].x)) & cur); ans[q[i].id] = upd.count(); } else { int lim = sqrt(q[i].x); for (int j = 1; j <= lim; ++j) { if (!(q[i].x % j)) { if (cnt[j] && cnt[q[i].x / j]) { ans[q[i].id] = 1; break; } } } } } for (int i = 1; i <= n; ++i) puts(ans[i] ? "yuno" : "yumi"); return 0; }
|