正题
题目链接:https://www.luogu.com.cn/problem/P5355
顺带一提的是P3674 小清新人渣的本愿是这题的弱化版,提交就可以A
题目大意
nnn个数字,询问
- 一个区间是否有两个数a,ba,ba,b使得a+b=xa+b=xa+b=x
- 一个区间是否有两个数a,ba,ba,b使得a−b=xa-b=xa−b=x
- 一个区间是否有两个数a,ba,ba,b使得a∗b=xa*b=xa∗b=x
- 一个区间是否有两个数a,ba,ba,b使得a/b=xa/b=xa/b=x
aaa和bbb可以是同一个数。
解题思路
下面默认n,mn,mn,m同级
莫队的话修改是O(nn)O(n\sqrt n)O(nn)次的但是询问是O(n)O(n)O(n)次的所以询问处可以操作一波。
对于前两个操作,开两个bitsetbitsetbitset,b1xb1_xb1x表示是否有xxx这一个数,b2xb2_xb2x表示是否有N−xN-xN−x这个数。
那么对于询问a+b=xa+b=xa+b=x就是询问(b1<<x)&b1(b1<<x)\& b1(b1<<x)&b1是否有值,询问a−b=xa-b=xa−b=x就是询问(b1<<(N−x))&b2(b1<<(N-x))\&b2(b1<<(N−x))&b2是否有值。上面的十分显然,并且bitsetbitsetbitset跑的也很快,可以通过。
然后询问a∗b=xa*b=xa∗b=x的话我们可以直接枚举xxx的约数即可,这样是O(n)O(\sqrt n)O(n)的
对于询问a/b=xa/b=xa/b=x的我们需要考虑根号分治,对于大于n\sqrt nn的我们就直接在莫队的时候枚举xxx的所有倍数。对于小于n\sqrt nn的因为只有n\sqrt nn个所以我们对于每个值可以O(n)O(n)O(n)搞。
假设目前为xxx,设resires_iresi表示以iii为右端点且有答案时最大的左端点位置,那么我们可以处理一个lastilast_ilasti表示上次iii出现的位置,然后没出用aia_iai和lastlastlast数组来更新resresres即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<bitset>
using namespace std;
const int N=1e5+10,T=300;
struct node{int op,l,r,x,id;
}q[N];
bitset<N> b1,b2;
int n,m,a[N],v[N],last[N],res[N];
bool ans[N];vector<int> qt[T+10];
bool cmp(node x,node y)
{return x.l/T==y.l/T?(x.r<y.r):(x.l<y.l);}
void add(int x){if(!v[x])b1[x]=1,b2[100000-x]=1;v[x]++;return;
}
void del(int x){if(v[x]==1)b1[x]=0,b2[100000-x]=0;v[x]--;return;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=m;i++){q[i].id=i;scanf("%d%d%d%d",&q[i].op,&q[i].l,&q[i].r,&q[i].x);}sort(q+1,q+1+m,cmp);int l=1,r=0;for(int i=1;i<=m;i++){if(q[i].op==4&&q[i].x<=T){qt[q[i].x].push_back(i);continue;}while(l<q[i].l)del(a[l]),l++;while(l>q[i].l)l--,add(a[l]);while(r<q[i].r)r++,add(a[r]);while(r>q[i].r)del(a[r]),r--;int x=q[i].x;if(q[i].op==1)ans[q[i].id]=(b1&(b1<<x)).any();else if(q[i].op==2)ans[q[i].id]=((b1<<(100000-x))&b2).any();else if(q[i].op==3){for(int j=1;j*j<=x;j++)if(x%j==0&&v[j]&&v[x/j]){ans[q[i].id]=1;break;}}else{for(int j=1;j*x<=1e5;j++)if(v[j]&&v[j*x]){ans[q[i].id]=1;break;}}}for(int x=1;x<=T;x++){if(qt[x].empty())continue;memset(last,0,sizeof(last));for(int i=1;i<=n;i++){last[a[i]]=i;res[i]=res[i-1];if(x*a[i]<=1e5)res[i]=max(res[i],last[x*a[i]]);if(a[i]%x==0)res[i]=max(res[i],last[x/a[i]]);}for(int p=0;p<qt[x].size();p++){int i=qt[x][p];ans[q[i].id]=(q[i].l<=res[q[i].r]);}}for(int i=1;i<=m;i++)puts(ans[i]?"hana":"bi");return 0;
}