[luogu3674]小清新人渣的本愿

题意简介

给定长度为\(n\)数列\(a\) ,\(m\)组查询,问\([l,r]\)内是否有两个数之和/差/积为\(x\),

\(n,m\le 10^5,max\{a\}\le10^5​\)

传送门

题解

bitset

我们先来介绍一下 bitset

如果您熟悉bitset请跳至下一章

bitset十分神奇,你可以把它看作一个支持整体操作的Bool数组。

bitset的原理是基于类似把long long拆成64个二进制位,从而使它的整体时间和空间降至\(O(\frac{N}{\omega})\)

其中,\(\omega=64\) (在64位机中)。

构造函数
    bitset<10> bs("0000000000");//0000000000
    //这里10表示这个bitset共十位,前面不够补0.
    //这里字符串既可以是一个string,也可以是char[]
    bitset<10> bs1(128);//0010000000
    bitset<2> bs2(128);//00
    //这里128=(0010000000),取末两位,string/char[]构造时同理。
运算
    bs=64;//0001000000
    bs|=11;//0001001011
    bs1&=2;//0000000010
    bs^=64;//0000001011
    bs<<=1;//0000010110
    bs>>=2;//0000000101
    bs2=~bs2;//11(按位取反)
    //bitset支持&,|,^,<<,>>,~和数字/bitset进行运算(也支持比较相等关系(==,!=))
函数
cout<<bs[2]<<endl;

//bitset支持取某一位的值
/*bs[] 0 1 2 3 4 5 6 7 8 9
       1 0 1 0 0 0 0 0 0 0
*/
cout<<bs.count()<<endl;//2
//count()用来计算bitset中1的个数
cout<<bs.size()<<endl;//10
//size()用来计算bitset的大小
cout<<bs.any()<<endl;//true
//any()用来计算bitset中是否有1
cout<<bs.none()<<' '<<bs.all()<<endl;//false false
//none(),all()分别返回bitset中是否全是0/1
//all()只能在c++11中使用

其中除 取某一位(如bs[2])复杂度为\(O(1)\) ,其余均为\(O(\frac{n}{w})\)

// flip()取反整个bitset或其中某位。
bitset<10> bs3("1110101111");
bs3.flip(); //0001010000
//相当于bs3=~bs3;
bs3.flip(1);//0001010010
//bs3[1]=!bs3[1];
    
// set()将整个bitset或其中某位设为1。
bs3.set();   //1111111111
bs3.set(3,0);//1111110111
bs3.set(3);  //1111111111

//reset()与set()类似
bs3.reset(3) //1111110111
bs3.reset()  //0000000000

其中除对某一位进行操作外,其余复杂度为\(O(n)\)

本题解法

莫队+bitset

我们先来考虑操作1

即找
\[ a-b=x \]

\[ a=b+x \]
我们用莫队 维护一个bitset(bs), bs的每一位维护一个数的出现情况

在查询时查询(bs&(bs<<x)).any()即可

操作2:

再来一次
\[ a+b=x \\ a=-b+x \]
bitset不可以维护负数,似乎很不可做,怎么办?

将维护负数的bitset(bs1)左移N位(N即为出现数的最大值)!

这样
\[ bs[i]=bs1[N-i] \]
查询时将bs1右移\(N-x\)位,即原负数bitset左移x位

即(bs&(bs1>>(N-x))).any()

操作3:

跳出思维定势!

x很小,直接枚举因数即可

复杂度即为\(O(m\sqrt m+m*\frac{n}{w})\)

应该能过

/*
  author:pmt
  program:luogu P3674
*/
#include<bits/stdc++.h>

#define LOCAL
#define mp make_pair
#define pb push_back
#define y0 _pmtY0
#define x0 _pmtX0
#define y1 _pmtY1
#define x1 _pmtX1
#define next _pmtNXT
#define pipe _pmtPPIE

#define lson(id) (id<<1)
#define rson(id) (id<<1|1)

using namespace std;

typedef long long ll ;
typedef unsigned long long ull ;
typedef vector<int > vi;
typedef vector<ll > vll;
typedef pair<int ,int > pii;
typedef vector<pii> vii;

inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    return s*w;
}
void write(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return;
}

const int inf=0x3f3f3f3f, maxn=100007,N=100007, mod=1e9+7;
const ll linf=0x3f3f3f3f3f3f3f3fLL;
const ll P=19260817;


int n,m;
bitset<maxn> bs1,bs2;
int a[maxn];
int cnt[maxn];
struct node{
    int l,r,id,k,x;
}q[maxn];
int B;
bool ans[maxn];
bool cmp(const node &a ,const node &b){
    if(a.l/B==b.l/B)return a.r<b.r;
    return a.l<b.l;
}

void del(int i){cnt[a[i]]--; if(!cnt[a[i]])bs1[a[i]]=bs2[N-a[i]]=false; }
void add(int i){if(!cnt[a[i]])bs1[a[i]]=bs2[N-a[i]]=true;  cnt[a[i]]++; }
int main(){    
    n=read(),m=read();
    B=sqrt(n);
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<=m;i++){
        q[i].k=read();
        q[i].l=read(),q[i].r=read();
        q[i].x=read();
        q[i].id=i;
    }
    sort(q+1,q+n+1,cmp);
    int l=0,r=0;
    for(int i=1;i<=m;i++){
        while(l<q[i].l)del(l++);
        while(l>q[i].l)add(--l);
        while(r>q[i].r)del(r--);
        while(r<q[i].r)add(++r);
        int k=q[i].k,x=q[i].x;
        if(k==1)ans[q[i].id]=(bs1 & (bs1<<x)).any();
        if(k==2)ans[q[i].id]=(bs1 & (bs2>>(N-x))).any();
        if(k==3){
            for(int j=1;j*j<=x;j++){
                if((!(x%j)&&bs1[j]&&bs1[x/j])){ans[q[i].id]=true;break;}
            }
        }
    }
    for(int i=1;i<=m;i++){
        printf("%s\n",(ans[i]?"hana":"bi"));
    }
    
    return 0;
}

转载于:https://www.cnblogs.com/pmt2018/p/11203926.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值