时空限制 3000ms / 128MB
题目描述
这个题是这样的:
给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3
选出的这两个数可以是同一个位置的数
输入格式:
第一行两个数n,m
后面一行n个数表示ai
后面m行每行四个数opt l r x
opt表示这个是第几种操作,l,r表示操作的区间,x表示这次操作的x
输出格式:
对于每个询问,如果可以,输出hana,否则输出bi
说明
定义c为每次的x和ai中的最大值,ai >= 0,每次的x>=2
对于100%的数据,n,m,c <= 100000
题目分析
题目没有要求强制在线,很快联想到了莫队
但说实话要是没有偷偷瞄一眼题解还真的没想到bitset这种黑科技
此题需要两个
b
i
t
s
e
t
bitset
bitset
r
e
m
1
rem1
rem1记录每个数字的出现情况,若
r
e
m
[
i
]
=
=
1
rem[i]==1
rem[i]==1,则代表当前区间存在数字
i
i
i
那么对于是否存在
a
−
b
=
x
a-b=x
a−b=x的询问,只需要检查
r
e
m
1
&
(
r
e
m
1
<
<
x
)
rem1\&(rem1<<x)
rem1&(rem1<<x)中是否存在1即可
b i t s e t bitset bitset有一个成员函数 a n y ( ) any() any()可以返回bitset中是否存在某一位是1,直接调用即可
对于是否存在
a
+
b
=
x
a+b=x
a+b=x的询问,还是需要一个bitset
r
e
m
2
rem2
rem2记录数字
N
−
x
N-x
N−x在当前区间是否存在(N可以是大于题目给定值域范围最大值的任何数)
r
e
m
2
[
i
]
=
=
1
rem2[i]==1
rem2[i]==1代表当前区间存在
N
−
i
N-i
N−i
为方便表示记
r
e
m
2
rem2
rem2第
i
i
i位为
i
′
i^{'}
i′
那么
a
+
b
=
x
a+b=x
a+b=x可以转化为
N
−
b
′
+
a
=
x
⇒
b
′
−
a
=
N
−
x
N-b^{'}+a=x\Rightarrow b^{'}-a=N-x
N−b′+a=x⇒b′−a=N−x
所以只需要检查
r
e
m
2
&
(
r
e
m
1
<
<
(
N
−
x
)
)
rem2\&(rem1<<(N-x))
rem2&(rem1<<(N−x))中是否存在1即可
对于是否存在
a
∗
b
=
x
a*b=x
a∗b=x的询问
直接枚举
x
x
x的约数,复杂度为
O
(
x
)
O(\sqrt{x})
O(x),完全可行
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
#include<bitset>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const int maxn=200010;
int n,m,t;
int a[maxn],ans[maxn];
int cnt[maxn],L=1,R=0;
bitset<maxn> rem1,rem2;
struct node{int opt,ll,rr,k,id;}q[maxn];
bool cmp(node a,node b){ return (a.ll/t)==(b.ll/t)?a.rr<b.rr:a.ll/t<b.ll/t;}
void add(int x,int k)
{
cnt[x]++;
if(cnt[x]==1)
rem1[x]=1,rem2[maxn-x]=1;
}
void del(int x,int k)
{
cnt[x]--;
if(cnt[x]==0)
rem1[x]=0,rem2[maxn-x]=0;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=m;++i)
{
q[i].id=i; q[i].opt=read();
q[i].ll=read(); q[i].rr=read();
q[i].k=read();
}
t=sqrt(n);
sort(q+1,q+1+m,cmp);
for(int i=1;i<=m;++i)
{
int judge=0;
while(R<q[i].rr) add(a[++R],q[i].k);
while(R>q[i].rr) del(a[R--],q[i].k);
while(L<q[i].ll) del(a[L++],q[i].k);
while(L>q[i].ll) add(a[--L],q[i].k);
if(q[i].opt==1&&(rem1&(rem1<<q[i].k)).any()) judge=1;
else if(q[i].opt==2&&((rem1<<(-q[i].k+maxn))&rem2).any()) judge=1;
else if(q[i].opt==3)
{
for(int j=1;j*j<=q[i].k;++j)
if(q[i].k%j==0){
if(cnt[j]&&cnt[q[i].k/j]){ judge=1; break;}
}
}
if(judge) ans[q[i].id]=1;
else ans[q[i].id]=0;
}
for(int i=1;i<=m;++i)
if(ans[i]) printf("hana\n");
else printf("bi\n");
return 0;
}