题意简介
给定长度为\(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;
}