4810: [Ynoi2017]由乃的玉米田

4810: [Ynoi2017]由乃的玉米田

Time Limit: 30 Sec   Memory Limit: 256 MB
Submit: 464   Solved: 222
[ Submit][ Status][ Discuss]

Description

由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美。这排玉米一共有N株,它们的高度参差不齐。
由乃认为玉米田不美,所以她决定出个数据结构题
 
这个题是这样的:
给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是
否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1
,2,3选出的这两个数可以是同一个位置的数

Input

第一行两个数n,m
后面一行n个数表示ai
后面m行每行四个数opt l r x
opt表示这个是第几种操作,l,r表示操作的区间,x表示这次操作的x
定义c为每次的x和ai中的最大值,ai >= 0,每次的x>=2n,m,c <= 100000

Output

对于每个询问,如果可以,输出yuno,否则输出yumi

Sample Input

5 5
1 1 2 3 4
2 1 1 2
1 1 2 2
3 1 1 1
3 5 5 16
1 2 3 4

Sample Output

yuno
yumi
yuno
yuno
yumi

HINT

Source

[ Submit][ Status][ Discuss]

离线询问然后用莫队算法解决
对于当前区间的数,维护一个bitset,第i位为1代表存在数字i,再维护一个bitset为它的翻转
1类询问等价于寻找a = b + x
那么把这个bitset左移x位然后取交集,有1就存在
2类询问就把翻转后的bitset右移一下
而3类询问完全可以暴力枚举质因子来做
#include<iostream>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cmath>
#include<algorithm>
using namespace std;
 
const int N = 100001;
const int maxn = 1E5 + 5;
 
struct Query{
    int l,r,op,x,key,Num; Query(){}
    Query(int l,int r,int op,int x,int key,int Num):
        l(l),r(r),op(op),x(x),key(key),Num(Num){};
    bool operator < (const Query &B) const
    {
        if (key < B.key) return 1;
        if (key > B.key) return 0;
        return r < B.r;
    }
}D[maxn];
 
int n,m,A[maxn],cnt[maxn];
bool Ans[maxn];
 
bitset <N> b1,b2;
 
inline void Insert(int pos)
{
    ++cnt[A[pos]];
    if (cnt[A[pos]] == 1)
        b1[A[pos]] = b2[N - 1 - A[pos]] = 1;
}
 
inline void Delete(int pos)
{
    --cnt[A[pos]];
    if (!cnt[A[pos]])
        b1[A[pos]] = b2[N - 1 - A[pos]] = 0;
}
 
inline bool Check1(int x)
{
    return (b1 & (b1 << x)).any();
}
 
inline bool Check2(int x)
{
    return (b1 & (b2 >> (N - 1 - x))).any();
}
 
inline bool Check3(int x)
{
    if (!x) return b1[0];
    for (int i = 1; i * i <= x; i++)
    {
        if (x % i != 0) continue;
        int a = i,b = x / i;
        if (b1[a] == 1 && b1[b] == 1) return 1;
    }
    return 0;
}
 
inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
        freopen("test.txt","w",stdout);
    #endif
     
    n = getint(); m = getint(); int Sqrt = sqrt(n);
    for (int i = 1; i <= n; i++) A[i] = getint();
    for (int i = 1; i <= m; i++)
    {
        int op,l,r,x;
        op = getint(); l = getint();
        r = getint(); x = getint();
        D[i] = Query(l,r,op,x,l / Sqrt,i);
    }
    sort(D + 1,D + m + 1);
     
    int L = 1,R = 0;
    for (int i = 1; i <= m; i++)
    {
        Query now = D[i];
        while (R > now.r) Delete(R--);
        while (R < now.r) Insert(++R);
        while (L < now.l) Delete(L++);
        while (L > now.l) Insert(--L);
        if (now.op == 1) Ans[now.Num] = Check1(now.x);
        else if (now.op == 2) Ans[now.Num] = Check2(now.x);
        else Ans[now.Num] = Check3(now.x);
    }
    for (int i = 1; i <= m; i++)
        puts(Ans[i] ? "yuno" : "yumi");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值