Luogu P5355 [Ynoi2017] 由乃的玉米田 题解
洛谷 P5355 [Ynoi2017] 由乃的玉米田
人生中第一道 Ynoi,多少得写点什么纪念一下。
题目链接
解析:
这道题算是P3674 小清新人渣的本愿的加强版,所以我们仍然可以使用类似的套路。
对于 , 操作,利用 bitset
来维护序列中数的出现情况, 操作直接枚举因数,不会的可以看我的这篇博客。
主要的问题是 操作,我们先考虑暴力枚举,设 ,使得 ,再判断 和 在 bitset
中是否出现过。
这样的复杂度是 的,可近似看做 的,其中 为数据的上限。
不难发现,当 越大时,枚举的次数越少。考虑根号分治,设定一个阀值 ,当 时,,可以保证复杂度最大是 的;当 时,我们不用莫队,单独处理。
考虑如何单独处理,对于每一个 ,从 到 遍历一遍 ,用 表示 最近一次出现的位置。
之后进行一个类似扫描线的操作。设序列中存在两个数 和 ,满足 的商为 ,即 或 。用 记录从位置 到 能找到的 的最靠右(最大)的位置。
然后我们考虑如何求出这个 数组。既然说过了是一个类似扫描线的操作,那我们不妨设这根“线”为 ,其记录着最近的 的位置 。 要么来源于 ,要么直接继承之前的 。所以,当 或 时,更新 ,最后的 即为 的值。
设询问的左端点为 ,右端点为 ,若 ,表示询问的区间内满足有两数的商为 。
Code
#include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e5 + 10, N = MAXN, SQ = 300; int n, m, siz, lim, tot; int num[MAXN], ans[MAXN]; int pre[MAXN], res[MAXN]; int belong[MAXN], temp[MAXN]; bitset<MAXN> add, cut; struct Question{ int opt, l, r, x, id; }q[MAXN]; vector<Question> p[MAXN]; bool cmp(const Question &a, const Question &b){ if(belong[a.l] != belong[b.l]) return belong[a.l] < belong[b.l]; if(belong[a.l] & 1) return a.r < b.r; return a.r > b.r; } inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } void Add(int x){ ++temp[x]; if(temp[x] == 1){ add[x] = 1; cut[N - x] = 1; } } void Del(int x){ --temp[x]; if(temp[x] == 0){ add[x] = 0; cut[N - x] = 0; } } bool Check_Add(int x){ return (add & (add << x)).any(); } bool Check_Cut(int x){ return (cut & (add << (N - x))).any(); } bool Check_Mul(int x){ for(register int d = 1; d * d <= x; d++){ if(x % d != 0) continue; if(add[d] && add[x / d]) return true; } return false; } bool Check_Div(int x){ for(register int d = 1; d * x <= MAXN; d++) if(add[d] && add[x * d]) return true; return false; } void Modify(int l, int r){ for(register int i = 1; i <= tot; i++){ int opt = q[i].opt, x = q[i].x; while(l < q[i].l) Del(num[l++]); while(l > q[i].l) Add(num[--l]); while(r < q[i].r) Add(num[++r]); while(r > q[i].r) Del(num[r--]); if(opt == 1) ans[q[i].id] = Check_Add(x); else if(opt == 2) ans[q[i].id] = Check_Cut(x); else if(opt == 3) ans[q[i].id] = Check_Mul(x); else if(opt == 4) ans[q[i].id] = Check_Div(x); } } void init(){ for(register int x = 1; x <= SQ; x++){ if(p[x].empty()) continue; int l = 0; memset(pre, 0, sizeof(pre)); for(register int i = 1; i <= n; i++){ pre[num[i]] = i; if(num[i] * x <= MAXN) l = max(l, pre[num[i] * x]); if(num[i] % x == 0) l = max(l, pre[num[i] / x]); res[i] = l; } for(register int i = 0; i < p[x].size(); i++){ if(p[x][i].l <= res[p[x][i].r]) ans[p[x][i].id] = 1; else ans[p[x][i].id] = 0; } } } int main(){ n = read(), m = read(); for(register int i = 1; i <= n; i++){ num[i] = read(); lim = max(lim, num[i]); } siz = sqrt(n); for(register int i = 1; i <= n; i++) belong[i] = (i - 1) / siz + 1; for(register int i = 1; i <= m; i++){ int opt, l, r, x; opt = read(), l = read(), r = read(), x = read(); if(opt == 4 && x <= SQ) p[x].push_back((Question){opt, l, r, x, i}); else q[++tot] = (Question){opt, l, r, x, i}; } init(); sort(q + 1, q + 1 + tot, cmp); Modify(1, 0); for(register int i = 1; i <= m; i++){ if(ans[i]) puts("yuno"); else puts("yumi"); } return 0; }
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16709749.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理