P5355 [Ynoi2017] 由乃的玉米田
阿新 • • 發佈:2022-04-19
思路
經典的 bitset
優化莫隊
先考慮減法:由 \(a-b=x\) 可得 \(a=b+x\),那麼我們用 bitset
記錄對應的數字是否出現過,然後在詢問時,我們將 bitset
整體向左移 \(x\) 位,再與原 bitset
取交集,如果不為 \(0\),顯然是可行的
然後加法與減法類似:考慮 \(a=Mx-a'\),那麼有 \(a-b'=a+b-Mx=x-Mx\),移項後 \(a+Mx-x=b'\),那我們就再用一個 bitset
維護 \(Mx-a\),詢問時與減法相同
乘法我們直接暴力列舉 \(\sqrt x\) 個因子進行判斷即可,複雜度與莫隊的複雜度是同階的
除法倒是有些棘手,我們考慮用根號分治:
-
若 \(x\ge \sqrt {Mx}\)(\(Mx\) 是最大的數),那麼我們直接像乘法那樣暴力列舉就行了
-
若 \(x< \sqrt{Mx}\),我們考慮不使用莫隊;我們對每種詢問 \(x\) 進行一次掃描線:\(la[num]\) 記錄 \(num\) 目前出現最靠右的位置,\(Rpos[i]\) 記錄掃到 \(i\) 時,滿足存在兩個數商為 \(x\)(沒有餘數)的最右左端點;流程如下:當掃到 \(i\) 時,將 \(la[a[i]]=i\),\(Rpos[i]=max(la[a[i]*x], la[a[i]/x],Rpos[i-1])\);處理詢問時,我們只需要比較 \(ql\)
程式碼
#include<iostream> #include<fstream> #include<algorithm> #include<cmath> #include<cstdlib> #include<cstring> #include<queue> #include<map> #include<set> #include<bitset> #define LL long long inline int reads() { int sign = 1, re = 0; char c = getchar(); while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();} while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();} return sign * re; } int n, m, len, Mx, Mxa, sq, a[100005], cl[100005]; struct Node { int op, l, r, x, id; }q[100005]; inline bool cmp(Node a, Node b) {return cl[a.l] ^ cl[b.l] ? a.l < b.l : a.r < b.r;} bool ans[100005]; int nl = 1, nr, cnt[100005]; std::bitset<100005> f, g; inline void add(int pos) {cnt[a[pos]]++; f[a[pos]] = g[Mx - a[pos]] = 1;} inline void del(int pos) {cnt[a[pos]]--; if(!cnt[a[pos]]) f[a[pos]] = g[Mx - a[pos]] = 0;} std::vector<int> ask[320]; int la[100005], Rpos[100005]; signed main() { #ifndef ONLINE_JUDGE freopen("test.in", "r", stdin); freopen("test.out", "w", stdout); #endif n = reads(), m = reads(); len = sqrt(n); for(int i = 1; i <= n; i++) a[i] = reads(), cl[i] = (i - 1) / len + 1, Mx = std::max(Mx, a[i]); Mxa = Mx; sq = sqrt(Mxa); for(int i = 1; i <= m; i++) q[i] = (Node){reads(), reads(), reads(), reads(), i}, Mx = std::max(Mx, q[i].x); std::sort(q + 1, q + 1 + m, cmp); for(int i = 1; i <= m; i++) { while(q[i].l < nl) add(--nl); while(q[i].r > nr) add(++nr); while(q[i].l > nl) del(nl++); while(q[i].r < nr) del(nr--); if(q[i].op == 2) ans[q[i].id] = (g & (f << (Mx - q[i].x))) != 0; else if(q[i].op == 1) ans[q[i].id] = (f & (f << q[i].x)) != 0; else if(q[i].op == 3) { for(int j = 1; j * j <= q[i].x; j++) if(!(q[i].x % j) && f[j] && f[q[i].x / j]) { ans[q[i].id] = true; break; } } else if(q[i].x >= sq) { for(int j = 1; j * q[i].x <= Mxa; j++) if(f[j] && f[j * q[i].x]) { ans[q[i].id] = true; break; } } else ask[q[i].x].emplace_back(i); } for(int i = 1; i < sq; i++) { if(ask[i].empty()) continue; for(int j = 1; j <= n; j++) { la[a[j]] = j; Rpos[j] = Rpos[j - 1]; if(a[j] * i <= Mxa) Rpos[j] = std::max(Rpos[j], la[a[j] * i]); if(!(a[j] % i)) Rpos[j] = std::max(Rpos[j], la[a[j] / i]); } for(const auto& id : ask[i]) ans[q[id].id] = (q[id].l <= Rpos[q[id].r]); memset(la, 0, sizeof(la)), memset(Rpos, 0, sizeof(Rpos)); } for(int i = 1; i <= m; i++) if(ans[i]) printf("yuno\n"); else printf("yumi\n"); return 0; }