[莫队]luogu3674 小清新人渣的本愿

题目

给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3

题解

这题用莫队和bitset和卡常
莫队的时间O( nn )
bitset时间除以64
总时间O(玄学???)
所以要卡常

1.读入优化
2.函数都要加inline(效果明显)
3.printf()用puts()代替
4.bitset.count()用bitset.any()代替(效果明显)

n=10^5时可以跑进1s

ac代码

#include<cstdio>
#include<algorithm>
#include<bitset>
#define N 100010
#define MX 100000
#define B 320
using namespace std;
inline int rd(){
    char c;
    int x=0,y=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')y=-1;
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x*y;
}
struct Que{
    int o,p,q,v,id;
}c[N];
bitset<N>f,g;
int b[N],v[N],n,m,ans[N],a[N],l,r;
inline bool cmp(Que p,Que q){
    if(b[p.p]==b[q.p])return p.q<q.q;
    return b[p.p]<b[q.p];
}
inline void Insert(int x){
    if(++v[a[x]]==1){
        f.set(a[x]);
        g.set(MX-a[x]);
    }
}
inline void Delete(int x){
    if(--v[a[x]]==0){
        f.reset(a[x]);
        g.reset(MX-a[x]);
    }
}
inline bool Solve(int o,int x){
    if(o==1)return (f&(f<<x)).any();
    if(o==2)return (g&(f<<(MX-x))).any();
    for(int i=1;i<=B;i++)if(x%i==0&&v[i]&&v[x/i])return 1;
    return 0;
}
int main(){
    freopen("data.txt","r",stdin);
    n=rd(),m=rd();
    for(int i=1;i<=n;i++)a[i]=rd();
    for(int i=1;i<=n;i++)b[i]=(i-1)/B+1;
    for(int i=1;i<=m;i++){
        c[i].o=rd(),c[i].p=rd(),c[i].q=rd(),c[i].v=rd();
        c[i].id=i;
    }
    sort(c+1,c+m+1,cmp);
    l=c[1].p; r=c[1].p-1; 
    for(int i=1;i<=m;i++){
        while(l<c[i].p)Delete(l++);
        while(l>c[i].p)Insert(--l);
        while(r<c[i].q)Insert(++r);
        while(r>c[i].q)Delete(r--);
        ans[c[i].id]=Solve(c[i].o,c[i].v);
    }
    for(int i=1;i<=m;i++)if(ans[i])puts("hana");
    else puts("bi");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值