P5355 [Ynoi Easy Round 2017] 由乃的玉米田 题解

前言

  • 怎么明天还有模拟赛啊啊啊啊啊啊啊啊啊算了来道 DS

正文

  • 嗷嗷嗷嗷嗷嗷嗷嗷呜呜呜呜呜
  • sbmqwm:模拟赛给我msjing打成啥子了
  • 其实有一道题就只有前三个操作,就是这个,msjing写完弱化后咕咕咕了好久才写这题
  • 难点在除法
  • 不会根号分治的请学一下,不过弱化版用不到

减法

  • 加减真好难理解啊,加上还鸽了这么久,呼呼呼
  • 欸我不会理解错了吧
  • sbmqwm:不好说,建议大家这段去正规题解处看,msjing打完模拟赛还没缓过来
  • 设选出的两个数为 \(a\)\(b\),我们暂且不管这两个数的大小关系(懒),会有 \(a - b = x\)
  • 这个显然没法很好地做,我们移项,有:

\[a = b + x \]

  • 你发现这个就还好
  • 我们开一个 \(bitset\) 来统计一个数是否出现过,设为 \(nw1\),用 \(bitset\) 是方便做与运算并创掉 \(64\) 的常数以及方便一些诡异操作
  • 我们发现将这个 \(bitset\) 左移 \(x\) 位,就可以使表示 \(b\) 存在变成表示 \(b + x = a\) 存在,将移位前后的 \(nw1\) 做一个与运算(\(b\)\(b + x = a\) 同时出现为 \(1\)),有 \(1\) 合法,没 \(1\) 不合法
  • 对了,\(bitset\) 有一个 any() 可以直接得是否有 \(1\),但msjing用的 count(),可以试一下

加法

  • 类比减法,我们再开一个 \(bitset\),但是维护方式与减法不同
  • 我们先看看需要做什么
  • \(a + b = x\) 可以转化为 \(a = x - b\),欸,你发现需要维护 \(b\)\(x - b\)
  • 我们发现这个东西不好弄,尤其是 \(-b\),我们可以让 \(b' = maxm - b \>\>\> (maxm = 10^5)\),用一个新的 \(bitset\) 维护 \(b'\),设为 \(nw2\),柿子变成:\(a = b' + x - maxm\),我们就可以让 \(nw2\) 右移 \(maxm - x\) 并与 \(nw1\) 做与运算,同上判断
  • 加减法复杂度(没算错的话)是 \(O(\frac{n^2}{\omega} + n \sqrt n)\)\(n\)\(m\) 同阶,后续复杂度都以 \(n\) 表示

乘法

  • 乘法就好理解了
  • 我们知道一个数 \(x\) 的约数不会超过 \(\sqrt x\),所以直接暴力枚举所有约数,若大小约数都在 \(nw1\) 中表示为 \(1\)(出现过),则直接停止枚举,答案合法,如果枚举完没成立的,答案不合法
  • 乘法复杂度是 \(O(n \sqrt n)\),可能吃不满

除法

  • 最难的来了
  • 我们发现这个东西根本做不了,先想想暴力
  • 我们可以尝试直接枚举除数,设为 \(j\),如果 \(j \times x\) 在值域 \(maxm\) 内就是合法的,所以就可以通过 \(nw1\) 检查 \(j\)\(j \times x\) 是否出现过了
  • 但是这只是一个纯暴力,显然复杂度不对
  • 我门尝试将这个暴力的复杂度控制在 \(O(n \sqrt n)\) 内,本身没法优化,只能减少枚举次数
  • 想到根号分治
  • 我们在 \(x > \sqrt {maxm}\) 的时候直接暴力做,别的等会考虑
  • 复杂度是 \(O(n \sqrt n)\)
  • 枚举貌似不可避免,那就枚举,反正前半段是 \(\sqrt n\) 的,相同的 \(x\) 直接一起枚举
  • 我们考虑一个位置 \(i\),能有贡献的是 \(a_i \times x\)\(a_i \>÷\> x\),当然,\(a_i \times x\) 成立要求 \(a_i \times x \le maxm\)\(a_i \>÷\> x\) 成立要求 \(x \mid a_i\)
  • 我们要统计对于 \(i\) 这个点,合法的 \(j\) 出现位置最大的地方,为什么等会就知道了,我们设这个数组为 \(g\),我们为了知道 \(a_i \times x\)\(a_i \>÷\> x\) 出现的位置,需要记录一下一个数 \(k\) 最后出现的位置,记为 \(pre_k\)
  • 实现的话,先让 \(pre_{a_i} = i\),然后查看 \(a_i \times x\)\(a_i \>÷\> x\) 是否合法,合法更新,最后对于一个询问 \([l,r]\),若 \(l \le g_r\),答案合法,反之不合法
  • 复杂度是 \(O(n \sqrt n)\)
  • 总复杂度是 \((\frac{n^2}{\omega} + n \sqrt n)\)
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define lb lower_bound
#define pb push_back
#define ph push
#define be begin()
#define ed end()
using namespace std;
constexpr int maxn=1e5+10,maxm=1e5;
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
    {
        if (ch == '-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        x=(x<<1)+(x<<3)+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int n,m;
int a[maxn];
struct _ {int op,l,r,x,id;}q[maxn];
vector<_> qu[maxn];
int L[maxn],R[maxn],pos[maxn];
bitset<maxn> nw1,nw2;
int col[maxn];
int pre[maxn],g[maxn];
void init()
{
    int b=n/(sqrt(m))+1;
    int cnt=n/b;
    for (int i=1;i<=cnt;i++)
        L[i]=b*(i-1)+1,R[i]=b*i;
    if (R[cnt]<n)
        cnt++,L[cnt]=R[cnt-1]+1,R[cnt]=n;
    for (int i=1;i<=cnt;i++)
        for (int j=L[i];j<=R[i];j++)
            pos[j]=i;
}
void add(int x)
{
    if (!col[x]) nw1.set(x),nw2.set(maxm-x);
    col[x]++;
}
void del(int x)
{
    col[x]--;
    if (!col[x]) nw1.reset(x),nw2.reset(maxm-x);
}
int ans[maxn];
signed main()
{
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=m;i++)
    {
        int op=read(),l=read(),r=read(),x=read();
        q[i]={op,l,r,x,i};
    }
    // cerr << "--------------" << endl;
    init();
    // cerr << "--------------" << endl;
    sort(q+1,q+1+m,[](_ a,_ b)
    {return pos[a.l] == pos[b.l] ?
     (pos[a.l]&1) ? a.r<b.r : a.r>b.r :
     pos[a.l]<pos[b.l];});
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        // cerr << i << " ";
        int x=q[i].x;
        while (l>q[i].l) add(a[--l]);
        while (r<q[i].r) add(a[++r]);
        while (l<q[i].l) del(a[l++]);
        while (r>q[i].r) del(a[r--]);
        if (q[i].op == 1)
        {
            if ((nw1&(nw1<<x)).count())
                ans[q[i].id]=1;
        }
        else if (q[i].op == 2)
        {
            if ((nw1&(nw2>>(maxm-x))).count())
                ans[q[i].id]=1;
        }
        else if (q[i].op == 3)
        {
            for (int j=1;j*j<=x;j++)
                if (!(x%j))
                    if (nw1[j] && nw1[x/j])
                    {
                        ans[q[i].id]=1;
                        break;
                    }
        }
        else
        {
            if (q[i].x>sqrt(maxm))
                for (int j=1;j*q[i].x<=maxm;j++)
                    if (nw1[j] && nw1[j*q[i].x])
                    {
                        ans[q[i].id]=1;
                        break;
                    }
        }
    }
    for (int i=1;i<=m;i++)
        if (q[i].op == 4 && q[i].x<=sqrt(maxm))
            qu[q[i].x].pb(q[i]);
    for (int x=1;x<=sqrt(maxm);x++)
    {
        if (qu[x].empty()) continue;
        memset(pre,0,sizeof(pre));
        memset(g,0,sizeof(g));
        int lt=0;
        for (int i=1;i<=maxm;i++)
        {
            pre[a[i]]=i;
            if (a[i]*x<=maxm)
                lt=max(lt,pre[a[i]*x]);
            if (!(a[i]%x))
                lt=max(lt,pre[a[i]/x]);
            g[i]=lt;
        }
        for (_ c:qu[x])
            ans[c.id]=c.l<=g[c.r] ? 1 : 0;
    }
    for (int i=1;i<=m;i++)
        ans[i] ? puts("yuno") : puts("yumi");
    return 0;
}

后话

  • 啊啊啊啊啊嗷嗷嗷嗷嗷嗷嗷嗷
  • sbmqwm:哎
posted @ 2026-08-16 21:11  msjing  阅读(5)  评论(0)    收藏  举报