码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P5355 [Ynoi2017]由乃的玉米田

时间:2020-01-20 12:58:29      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:div   using   href   update   dig   www   inline   ring   cstring   

Link
开一个桶记录每个数字出现过多少次,同时用bitset维护\(x\)是否出现过。
那么查询是否有两个数的差为\(x\)就是把bitset右移\(x\)位然后与自己,如果有位置为\(1\)那么就说明存在。
查询是否有两个数的和为\(x\)也可以类似地做,多开一个bitset维护\(10^5-x\)是否出现过。
查询是否有两个数的积为\(x\)可以直接枚举因数查询,注意特判\(x=0\)的情况。
最后是查询是否有两个数的商为\(x\),首先特判\(x=0\)的情况,对于\(x\ge64\)的数据,我们可以暴力枚举判断。
对于\(1\le x<64\)的,我们把所有\(x\)相同询问的放一起并按左端点降序排序,用树状数组维护一下以每个点为左端点的最左右端点就好了。
时间复杂度是\(O(\frac{n^2}{64}+n\sqrt n+64n\log n)\)
(实际上除法那里最优的分治边界应该是\(\sqrt{\frac n{\log n}}\),这样复杂度就是\(O(\frac{n^2}{64}+n\sqrt{n\log n})\),不过\(64\)也差不多)

#pragma GCC optimize(3)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<cstring>
#include<algorithm>
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}using IO::read;
using std::sort;
using std::bitset;
int min(int a,int b){return a<b? a:b;}
const int N=100007,U=100000,inf=0x3f3f3f3f;
bitset<N>S,T;
int n,m,bel[N],t[N],pos[N],a[N],ans[N];
struct node{int o,l,r,x,id;}q[N],p[N];
int operator<(const node&a,const node&b){return bel[a.l]==bel[b.l]? a.r<b.r:a.l<b.l;}
void add(int x){if(++t[x]==1)S[x]=T[U-x]=1;}
void del(int x){if(!--t[x])S[x]=T[U-x]=0;}
int askmul(int x){if(!x)return S[0];for(int i=1;i*i<=x;++i)if(!(x%i)&&S[i]&&S[x/i])return 1;return 0;}
int askdiv(int x){if(!x)return S[0]&&S.count()>1;for(int i=1,j=x;j<=U;++i,j+=x)if(S[i]&&S[j])return 1;return 0;}
void update(int p,int v){for(;p<=n;p+=p&-p)t[p]=min(t[p],v);}
int query(int p){int r=inf;for(;p;p^=p&-p)r=min(r,t[p]);return r;}
int main()
{
    n=read(),m=read();int c=0,B=sqrt(n)+rand()%5;
    for(int i=1;i<=n;++i) a[i]=read(),bel[i]=(i-1)/B+1;
    for(int i=1;i<=m;++i) q[i]={read(),read(),read(),read(),i};
    sort(q+1,q+m+1);
    for(int i=1,L=1,R=0;i<=m;++i)
    {
    int l=q[i].l,r=q[i].r,x=q[i].x;
    if(q[i].o==4&&q[i].x<64&&q[i].x) {p[++c]=q[i];continue;}
    while(l<L) add(a[--L]);
    while(R<r) add(a[++R]);
    while(L<l) del(a[L++]);
    while(r<R) del(a[R--]);
    if(q[i].o==1) ans[q[i].id]=(S&S<<x).any();
    else if(q[i].o==2) ans[q[i].id]=(S&T>>(U-x)).any();
    else if(q[i].o==3) ans[q[i].id]=askmul(x);
    else ans[q[i].id]=askdiv(x);
    }
    sort(p+1,p+c+1,[](const node&a,const node&b){return a.x<b.x||(a.x==b.x&&a.l>b.l);});
    for(int l=1,r;l<=c;l=r+1)
    {
    for(r=l;p[r+1].x==p[l].x&&r<c;++r);
    memset(t,0x3f,sizeof t),memset(pos,0x3f,sizeof pos);
    for(int i=l,j=n;i<=r;++i)
        {
            for(;j>=p[i].l;--j)
            {
        pos[a[j]]=j;
        if(1ll*a[j]*p[l].x<=U) update(j,pos[a[j]*p[l].x]);
        if(!(a[j]%p[l].x)) update(j,pos[a[j]/p[l].x]);
            }
        ans[p[i].id]=p[i].l>p[i].r? 0:query(p[i].r)<=p[i].r;
        }
    }
    for(int i=1;i<=m;++i) puts(ans[i]? "yuno":"yumi");
}

Luogu P5355 [Ynoi2017]由乃的玉米田

标签:div   using   href   update   dig   www   inline   ring   cstring   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12217302.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!