[Ynoi2017] 由乃的玉米田

题目链接 : [Ynoi2017] 由乃的玉米田

弱化版 : 小清新人渣的本愿

这两道题都是看会不会用bitset,bitset大胜利

  1. 减操作 : 用一个bitset vis1 记录一个数是否出现,如果有就是(vis1&(vis>>x)).count()1,其实就是看是否有数a和数a+x同时出现

  2. 加操作 : 同减操作,但是要转化一下,就是a+b=xa(100000b)=x100000。记录一个相反的bitset vis2,然后就是判断是否 (vis1&(vis2>>(100000x))).count()1(因为vis2是相反的bitset,所以不是右移x100000位而是100000x位)

  3. 乘操作 : O(x)暴力跑即可

  4. 除操作 : 根号分治

    1. x100000的暴力跑,复杂度是正确的O(n)
    2. 对于x<100000的,将其特殊处理

    定义两个数组 : prex表示x上一次(包括当前位置,因为一个位置可以重复选两次)出现的位置,lastposi表示到i时最后一个合法点对(i,j)(ij)i的位置。

    然后将所有op=4&x<100000的单独记录出来,单独处理。

    枚举x,然后用一个指针iO(n)扫一遍a,假设当前扫到的位置为i,记录当前最后一个合法点对(i,j)i的位置为res,依次执行以下操作 :

    1. i替换preai
    2. 如果ai×x100000,那么res=max(res,preai×x)
    3. 如果aimodx=0,那么res=max(res,preaix)

    最后统计一下答案,就是比较llastposr的大小关系,如果l>lastposr则无解。

预处理的复杂度是O(nn),莫队的复杂度是O(n(n+nw))的,可以通过,无需卡常

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10,M = 330;
int n,m,a[N],L[M],R[M],pos[N],len,ct[N];
struct node{int op,l,r,x,id;}q[N];int cnt = 0;
bool ans[N];
struct Node{int l,r,id;};
vector<Node> p[M];
int pre[N],lastpos[N];
inline void solve(){
cin>>n>>m;
for(int i = 1;i <= n; ++i) cin>>a[i];
for(int i = 1,op,l,r,x;i <= m; ++i){
cin>>op>>l>>r>>x;
if(op == 4 && x < M) p[x].emplace_back((Node){l,r,i});
else q[++cnt] = {op,l,r,x,i};
}
for(auto i:p[1]) ans[i.id] = true;
for(int now = 2;now < M; ++now){
if(p[now].empty()) continue;
int res = 0;
memset(lastpos,0,sizeof lastpos);
memset(pre,0,sizeof pre);
for(int i = 1;i <= n; ++i){
int y = a[i];
pre[y] = i;
if(now * y <= 100000) res = max(res,pre[now*y]);
if(y % now == 0) res = max(res,pre[y/now]);
lastpos[i] = res;
}
for(auto i : p[now]) ans[i.id] = (i.l <= lastpos[i.r]);
}
len = sqrt(n);
for(int i = 1;i <= len; ++i) L[i] = R[i - 1] + 1,R[i] = i * len;
if(R[len] < n) len ++, L[len] = R[len - 1] + 1,R[len] = n;
for(int i = 1;i <= len; ++i) for(int j = L[i];j <= R[i]; ++j) pos[j] = i;
sort(q+1,q+1+cnt,[](node x,node y){return (pos[x.l]==pos[y.l]?(pos[x.l]&1?x.r<y.r:x.r>y.r):x.l<y.l);});
bitset<N> vis1,vis2;
int left = 1,right = 0;
auto add = [&](int x) -> void{
if(!ct[x])vis1[x] = vis2[100000 - x] = true;
ct[x]++;
};
auto del = [&](int x) -> void{
ct[x]--;
if(!ct[x]) vis1[x] = vis2[100000 - x] = false;
};
for(int i = 1;i <= cnt; ++i){
int l = q[i].l,r = q[i].r,op = q[i].op,x = q[i].x;
while(left > l) add(a[--left]);
while(right < r) add(a[++right]);
while(left < l) del(a[left++]);
while(right > r) del(a[right--]);
if(op == 1) ans[q[i].id] = (vis1&(vis1>>x)).count();
if(op == 2) ans[q[i].id] = (vis1&(vis2>>(100000-x))).count();
if(op == 3){
int k = sqrt(x);
for(int j = 1;j <= k; ++j){
if(x % j == 0 && vis1[j] && vis1[x/j]){ans[q[i].id] = true;break;}
}
}
if(op == 4){
for(int j = 1;j <= 100000/x; ++j) if(vis1[j] && vis1[j*x]){ans[q[i].id] = true;break;}
}
}
for(int i = 1;i <= m; ++i) cout<<(ans[i]?"yuno\n":"yumi\n");
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
solve();
}
posted @   CuFeO4  阅读(29)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示