来自FallDream的博客,未经允许,请勿转载,谢谢。
bzoj被疯狂卡评测,题解只好堆在一起写了
------------------------------------
由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美。这排玉米一共有N株,它们的高度参差不齐。
由乃认为玉米田不美,所以她决定出个数据结构题
这个题是这样的:
给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3选出的这两个数可以是同一个位置的数
n,m<=100000 ai<=100000 time limit:3s
上次看题目貌似没看到数的大小 然后感觉不可做TAT
没有强制在线,考虑莫队
然后我们要怎么判断呢?由于数字很小,所以可以开一个bitset假设叫a,记录每种数字是否出现。
对于询问1,只要把这个bitset左移那么多位,与一下,判断是否有1就行了。
对于询问2,x=a+b相当于a=x-b,考虑再开一个bitset假设叫b,第i位记录MN-i是否出现,那么变成判断是否有 a+MN=x+MN-b 也就是把a左移MN位,b左移x位,与一下,当然实际上你只要把a左移MN-x位就行了。
对于询问3,发现可能的情况很少,所以可以打表因数,然后直接暴力check就行了。
复杂度是$O(n^{\frac{3}{2}}+\frac{n^{2}}{32})$
#include<iostream> #include<cstdio> #include<bitset> #include<vector> #include<algorithm> #include<cmath> #define MN 100000 using namespace std; inline int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } vector<int> v[MN+5]; bitset<MN+1> a,b; bool ans[MN+5]; int s[MN+5],n,m,size,block[MN+5],L,R,f[MN+5]; struct ques { int kind,l,r,x,num; bool operator<(const ques&y)const{return block[l]==block[y.l]?r<y.r:l<y.l;} }q[MN+5]; inline void ins(int x){if(!f[s[x]]++) a[s[x]]=b[MN-s[x]]=1;} inline void del(int x){if(!--f[s[x]]) a[s[x]]=b[MN-s[x]]=0;} int main() { n=read();m=read();size=sqrt(n); for(int i=1;i<=n;i++) s[i]=read(); for(int i=1;i<=n;i++) block[i]=(i-1)/size+1; for(int i=1;i<=m;i++) q[i].kind=read(),q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].num=i; sort(q+1,q+m+1); ins(L=R=1); for(int i=1;i*i<=MN;i++) for(int j=i*i;j<=MN;j+=i) v[j].push_back(i); for(int i=1;i<=m;i++) { while(L<q[i].l)del(L++); while(L>q[i].l)ins(--L); while(R<q[i].r)ins(++R); while(R>q[i].r)del(R--); if(q[i].kind==1) ans[q[i].num]=((a<<q[i].x)&a).count()?1:0; if(q[i].kind==2) ans[q[i].num]=((a<<(MN-q[i].x))&b).count()?1:0; if(q[i].kind==3) for(int j=0;j<v[q[i].x].size();j++) if(a[v[q[i].x][j]]&&a[q[i].x/v[q[i].x][j]]) {ans[q[i].num]=1;break;} } for(int i=1;i<=m;i++)ans[i]?puts("yuno"):puts("yumi"); return 0; }