BZOJ4810: [Ynoi2017]由乃的玉米田

【传送门:BZOJ4810


简要题意:

  给出n个数,给出m种询问:

  1 l r x判断是否在区间l到r中能选出两个数的差为x

  2 l r x判断是否在区间l到r中能选出两个数的和为x

  3 l r x判断是否在区间l到r中能选出两个数的乘积为x

  其中选出的两个数可以相等


题解:

  肯定得离线

  用莫队吧(离线,第一时间就想到莫队)

  第三个询问可以暴力求因子搞一搞

  结果发现不会搞1和2

  上网搜了搜,学了一波bitset

  bitset简单来说可以当作一个二进制位来用,但是它并不需要二进制那样的庞大数据范围

  而且赋值只需要像数组一样赋值

  然后对于第1个操作,将当前bitset与当前的bitset向右移x位之后的bitset做一下and运算,假如有1,则说明成立

  然后对于第2个操作,将用第二个bitset作为第一个bitset的取反,然后用反转bitset右移后和正bitset做一下and运算,如果有1,则说明成立(这个东西,自己脑补,也挺容易理解的)


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<bitset>
using namespace std;
bitset<110000> bs1,bs2;
int a[110000];
int belong[110000];
struct node
{
    int opt,l,r,x,d,id;
}q[1100000];int n,m;
bool cmp1(node n1,node n2)
{
    if(belong[n1.l]<belong[n2.l]) return true;
    if(belong[n1.l]>belong[n2.l]) return false;
    if(belong[n1.l]==belong[n2.l])
    {
        if(n1.r<n2.r) return true;
        if(n1.r>n2.r) return false;
    }
    return false;
}
bool cmp2(node n1,node n2)
{
    return n1.id<n2.id;
}
int sum[110000];
void add(int x)
{
    sum[x]++;
    if(sum[x]==1) bs1[x]=1,bs2[n-x+1]=1;
}
void del(int x)
{
    sum[x]--;
    if(sum[x]==0) bs1[x]=0,bs2[n-x+1]=0;
}
int solve1(int x)
{
    if(((bs1)&(bs1>>x)).any()==true) return 1;
    else return 0;
}
int solve2(int x)
{
    if(((bs1)&(bs2>>(n-x+1))).any()==true) return 1;
    else return 0;
}
int solve3(int x)
{
    int t=int(sqrt(x+1));
    for(int i=1;i<=t;i++) if(x%i==0&&bs1[i]==1&&bs1[x/i]==1) return 1;
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int block=int(sqrt(n));
    for(int i=1;i<=n;i++)
    {
        int t=(i-1)/block+1;
        belong[i]=t;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&q[i].opt,&q[i].l,&q[i].r,&q[i].x);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp1);
    int l=1,r=0;
    memset(sum,0,sizeof(sum));
    bs1.reset();bs2.reset();
    for(int i=1;i<=m;i++)
    {
        while(l>q[i].l){l--;add(a[l]);}
        while(l<q[i].l){del(a[l]);l++;}
        while(r>q[i].r){del(a[r]);r--;}
        while(r<q[i].r){r++;add(a[r]);}
        if(q[i].opt==1) q[i].d=solve1(q[i].x);
        if(q[i].opt==2) q[i].d=solve2(q[i].x);
        if(q[i].opt==3) q[i].d=solve3(q[i].x);
    }
    sort(q+1,q+m+1,cmp2);
    for(int i=1;i<=m;i++) if(q[i].d==1) printf("yuno\n"); else printf("yumi\n");
    return 0;
}

 

posted @ 2018-03-12 21:09  Star_Feel  阅读(181)  评论(0编辑  收藏  举报