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:哎

浙公网安备 33010602011771号