• [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;
    }
    
    
  • 相关阅读:
    正则表达式(验证账号密码邮箱身份证)
    JS Fetch
    事件流动
    JS DOM和BOM
    CSS的定位
    For each...in / For...in / For...of 的解释和例子
    CSS的gridlayout
    CSS position属性
    CSS的颜色
    twelfth week
  • 原文地址:https://www.cnblogs.com/pmt2018/p/11203926.html
Copyright © 2020-2023  润新知