P3674 小清新人渣的本愿

P3674 小清新人渣的本愿

题目背景

本题时限3s,空间128MB

我感觉我要挂省选

人渣的本愿是一个有趣的番

可爱的花火喜欢从小和她谈♂笑♂风♂生的欧♂尼♂酱鸣海,欧尼酱特别想当老师,然后剧本安排当了花火的班主任。

然而有个叫做皆川茜的奇怪的人抢走了欧尼酱!

花火就很失落呀,然后看到一个叫做麦的人也很失落,原来麦喜欢茜老师。。。

花火和麦从此天天谈笑风生,然后决定在一起,把对方当做自己喜欢的人的替代品

因为花火很可爱,所以有许多奇怪的人喜欢花火,比如一个叫做绘鸠早苗的妹子

因为麦长的也不错,所以有许多奇怪的人喜欢麦,比如一个叫做最可的妹子

然后就开始愉快的生♂活了~

以上内容如果你没有看过这个番可以无视掉

按照套路,现在欧尼酱会问花火一个OI问题(一般是数据结构),然后花火肯定不会OI,所以会来请教您这位IOI Au选手,然后您肯定会帮助她

但是
这个套路太无聊了,我们来换一个(但是不会改变您是IOI Au选手的事实)

花火有一天看了几个有趣的番,叫做“在W??身上寻找女装是否搞错了什么”,“从女装开始的?X?”,“我家大佬不可能那么可爱”,然后发现??H太厉害了,然后就穿越到了异世界,和???谈笑风生

花火就和???做了一个交♂易,花火帮???做一道题,然后???帮花火改写地球online的程序,让花火和欧尼酱在♂一♂起

???虽然非常厉害,但是不会数据结构题,他最近刚刚遇到一道有趣的数据结构题,于是他接受了交易

但是花火也不会数据结构题呀

所以又回到了这个老套路,就靠您这个IOI Au选手来帮她了!

以上内容如果你没有看过这个番还是可以无视掉

这里用一个经典的图来解释这个关系(其实没那么蛋疼的)

题目描述

这个题是这样的:

给你一个序列 \(a\),长度为 \(n\),有 \(m\) 次操作,每次询问一个区间是否可以选出两个数它们的差为 \(x\),或者询问一个区间是否可以选出两个数它们的和为 \(x\),或者询问一个区间是否可以选出两个数它们的乘积为 \(x\) ,这三个操作分别为操作 \(1,2,3\)

选出的这两个数可以是同一个位置的数。

输入格式

第一行两个数 \(n,m\)

后面一行 \(n\) 个数表示 \(a_i\)

后面 \(m\) 行每行四个数 opt l r x

\(opt\) 表示这个是第几种操作,\(l,r\) 表示操作的区间,\(x\) 表示这次操作的 \(x\)

输出格式

对于每个询问,如果可以,输出 hana,否则输出 bi

说明/提示

对于 \(100\%\) 的数据,\(n,m,c \leq 10^5\)

Solution:

bitset 好题,lxl哥哥是好人%%%

先解决前两问:
我们使用一个 bitset \(f\) 来维护一个数字在当前区间上是否出现过。
对于 \(a-b=x:\)

  • 对于任意的 \(a\),只要 \(a,a-x\)\(f\) 中同时出现,即 $ f \text{ and } f \text{ << } x \ne 0$ 那么这个询问的答案就是 ture,否则是 falase.

对于 \(a+b=x:\)
我们维护另一个 bitset \(g\),用来表示 \(f\) 的翻转。\(f_i\) 对应了 \(g_{N-i}\)。这样一来,我们在 \(f\) 上找a,在 \(g\) 上找 \(b\),则有:

\(a-(N-b)=x-N\)

类似的,只要满足 \((f \text{ and }(g \text{ >> } (N-q[i].x))\ne 0\) 这个询问的答案就是 ture,否则是 falase.

然后是看起来很难,其实很简单的第三问。我们发现值域是 \(10^5\) 级别的,所以我们完全可以 \(O(\sqrt c)\) 枚举 \(x\) 的因子 \(d\) ,查询 \(d,\frac{x}{d}\) 是否同时存在就好了。

时间复杂度 \(O(\frac{n^2}{w})\),然后这题就做完了。

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=1e5;
#define _(x) (inf-x)
bitset<N> f,g,ans;
int n,m,len,cnt;
int bl[N],a[N],t[N];
void build()
{
    len=sqrt(n);cnt=n/len;
    cnt+=(n%len!=1);
    for(int i=1;i<=n;i++)
    {
        bl[i]=(i-1)/len+1;
    }
}
struct task{
    int opt,l,r,x,id;
    bool operator <(const task &t)const{
        return bl[l]==bl[t.l] ? (bl[l]&1 ?  r<t.r : t.r<r) : l<t.l;
    }
}q[N];
void add(int x)
{
    t[x]++;
    if(t[x]==1)f[x]=g[_(x)]=1;
}
void del(int x)
{
    t[x]--;
    if(!t[x])f[x]=g[_(x)]=0;
}
void work()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    build();
    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+1+m);
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(l<q[i].l)del(a[l++]);
        while(q[i].l<l)add(a[--l]);
        while(r<q[i].r)add(a[++r]);
        while(q[i].r<r)del(a[r--]);
        if(q[i].opt==1)
        {
            ans[q[i].id]=((f&(f<<q[i].x)).any());
        }
        if(q[i].opt==2)
        {
            ans[q[i].id]=((f&(g>>_(q[i].x))).any());
        }
        if(q[i].opt==3)
        {
            int lim=sqrt(q[i].x);
            for(int d=1;d<=lim;d++)if(q[i].x%d==0)
            {
                if(f[d]&f[q[i].x/d]){ans[q[i].id]=1;break;}
            }
        }
    }
    for(int i=1;i<=m;i++)printf(ans[i] ?  "hana\n" : "bi\n");
}
int main()
{
    //freopen("P3674.in","r",stdin);
    //freopen("P3674.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-08-06 14:15  liuboom  阅读(5)  评论(0)    收藏  举报