zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    洛朗级数
    泰勒级数
    中心极限定理
    置信区间公式
    简单随机样本的性质
    极大似然估计
    矩估计法
    摆摊70
    天天去哪吃
    天天和树
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4810.html
Copyright © 2011-2022 走看看