[bzoj4810][Ynoi2017]由乃的玉米田

来自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;
}

 

posted @ 2017-04-15 20:37  FallDream  阅读(362)  评论(0编辑  收藏  举报