Ynoi做题笔记
搬运自洛谷博客,原发表时间:2022-07-20
大致按照我感觉的难度排序。做了十四五道的样子,可以慢慢胡了。
评分标准:
技术力+思维力+代码力+卡常力
水平不够,评分暂时撤掉。
P3934 [Ynoi2016] 炸脖龙 I
题意:区间加,区间幂塔。
先考虑如何维护区间加+单点查询。很显然地,使用树状数组维护差分数组,前缀和即为该点的值。时间复杂度为 \(O(\log n)\),常数较小。
使用扩展欧拉定理处理幂塔。设模数为 \(p\),则 \(\varphi(p),\varphi(\varphi(p)),\varphi(\varphi(\varphi(p)))...\) 模数在 \(\log p\) 次后减小到 \(1\),因此递归求解幂塔,时间复杂度为 \(O(\log p)\)。由于递归时需要进行树状数组的单点查询,因此总时间复杂度为 \(O(\log p \log n)\)。
由于需要计算 \(\varphi(p)\),线性筛预处理 \(\varphi\) 数组即可。预处理复杂度为 \(O(p)\)。
总时间复杂度为 \(O(n+p+q \log p \log n)\)。
技术力比较高一些,感觉实际难度并不大。
P5309 [Ynoi2011] 初始化
题意:将所有编号形如 \(y+kx\) 的数加上 \(z\),区间查询。
根号分治,设临界值为 \(L\)。
对于 \(x \geq L\) 的情况,暴力修改即可。
而若 \(x < L\) ,则考虑分块,计算不完整块的前后缀和与整块的 \(sum\) 相加即可。
取 \(L=O(\sqrt{n})\),两种情况时间复杂度均为 \(O(\sqrt{n})\)。
总时间复杂度为 \(O(m\sqrt{n})\)。
个人认为略微卡常,临界值 \(L\) 取 \(\dfrac{3}{5}\sqrt{n}\) 时较优。
P5524 [Ynoi2012] NOIP2015 充满了希望
题意:操作:交换两点点权,区间赋值,单点查;查询:一段操作区间得到的结果之和。
维护每个位置最后一次修改的时间戳,单点查询记录当前的值,使用线段树维护;查询按右端点排序,单点查时在时间戳上加上其结果,答案即为区间和,使用树状数组维护。
时间复杂度 \(O(m \log n+q \log m)\)。
P8511 [Ynoi Easy Round 2021] TEST_68
题意:一棵树,对于每个节点求其子树以外的任何两节点的最大异或和。
首先考虑整棵树,求出其最大异或和 \(bst\),及得到该数的两点 \(x,y\)。
显然非 \(x\) 或 \(y\) 的祖先的所有节点的答案即为 \(bst\)。
考虑 \(x\) 或 \(y\) 的祖先:自顶向下,每次就增加了一定的点,分别对两条路径求最大异或和。
总时间复杂度 \(O(n \log a)\),\(a\) 为值域。
P5527 [Ynoi2012] NOIP2016 人生巅峰
题意:区间修改为原数的三次方,区间查询是否存在某两个子序列的和相等。
注意到可能的子序列的数量为 \(2^{r-l+1}-1\) 个,而可能的和至多 \(mod \times (r-l+1)\) 种。由抽屉原理,\(r-l+1 > 13\) 时,答案必为 Yuno。
\(r-l+1 \le 13\) 时直接枚举即可,每个位置的值可以通过预处理快速得到,使用树状数组维护修改次数即可。
时间复杂度 \(O(m \log n+m \times 2^{13} \times 13)\)。可以优化,但足以通过。
P4689 [Ynoi2016] 这是我自己的发明
题意:一棵树,支持换根,求树上两点的子树内相同数的个数。
- 前置问题:link
有 \(\text{get}(l,r,x)=\text{get}(1,r,x)-\text{get}(1,l-1,x)\)。
设 \(\text{g}(i,x)=\text{get}(1,i,x)\)。
则问询可转化为 \(\sum _{i=1} ^\infty (\text{g}(r_1,x) \text{g}(r_2,x)-\text{g}(r_1,x)\text{g}(l_2-1,x)-\text{g}(l_1-1,x)\text{g}(r_2,x)+\text{g}(l_1-1,x)\text{g}(l_2-1,x))\)。
拆成如上4个操作后,莫队计算即可,时间复杂度 \(O(n \sqrt n)\)。
- 回到原题
不考虑换根操作,将节点投射到 dfs 序上,则子树为一段连续区间,即与P5268类似。
考虑静态处理换根:若当前根在 \(x\) 原子树内,设 \(t\) 为 \(x\) 的原儿子中为当前根原祖先的那个(\(t\) 可与当前根重合),则 \(x\) 的当前子树为整棵树除去 \(t\) 的原子树的部分。
(此处拆为2个区间,再与 \(y\) 的区间分别产生莫队操作)
理性看待此题卡常:莫队操作数最大可达到 \(16 \times 5 \cdot 10^5=8 \times 10^6\)。
取块长 \(L=\dfrac{n}{\sqrt{m}}\),时间复杂度 \(O(n \sqrt m)\)。(写法较为重要)
P5607 [Ynoi2013] 无力回天 NOI2017
题意:区间异或上 \(v\),区间与 \(v\) 最大异或
区间操作,与炸脖龙一样的思路想到差分,转化为单点修改。维护树状数组的时间复杂度为 \(O(m \log n)\)。
设差分数组 \(b_i=a_i \oplus a_{i-1}\),则 \(a_i=b_1 \oplus b_2 \oplus ... \oplus b_i\)。
有一个性质(这一步非常妙,查看了题解才想出来):\(\left\{ a_l,a_{l+1},...,a_r \right\}\) 的线性基 \(=\) \(\left\{ a_l,b_{l+1},...,b_r \right\}\) 的线性基。
感性证明:因为 \(\left\{ a_l,a_{l+1},...,a_r \right\}\) 中的数都能用 \(\left\{ a_l,b_{l+1},...,b_r \right\}\) 的某种异或表示出来,得证。
于是就不难想到使用线段树维护 \(b\) 数组的线性基,区间查询时求 \(a_l \cup b_{[l+1,r]}\) 即可。
总时间复杂度 \(O((n+m) \log n \log ^2 V)\),空间复杂度 \(O(n \log V)\)(\(V\) 为值域)。
好像不怎么卡常。难点在于将原数组查询转换为差分数组查询的性质。
P5610 [Ynoi2013] 大学
题意:区间将 \(x\) 的倍数除以 \(x\),区间查询
对于一个数 \(a\),至多对其操作 \(d(a)\) 次。考虑从这个性质入手,用树状数组维护,时间复杂度为 \(O(n \, d(a) \log n)\)。
接下来考虑如何维护 \(x\) 的倍数集合。使用并查集快速查找下一个 \(x\) 倍数的位置。时间复杂度为 \(O(n \, d(a) \, \alpha(n))\)。
总时间复杂度为 \(O(n \, d(a) \log n+n \, d(a) \, \alpha(n))\)。
个人认为较为卡常,也许是这个方法常数较大。(upd:似乎不手写内存也能过)
P5356 [Ynoi2017] 由乃打扑克
题意:区间加,区间第 \(k\) 小。
分块,块内排序。(排序后的数组最好附带一个原数组的编号)
(以下 \(L\) 表示块长)
- 区间加
整块打 \(\text{tag}\),散块中挑出区间内的数(有序),修改后和剩下的数归并排序得到整块的有序数组。
时间复杂度为 \(O(L+\dfrac{n}{L})\)。
- 区间第 \(k\) 小
散块通过归并排序为一组,一整块单独为一组。值域中二分答案,在每组中求出大于其的个数,判断加起来后是否达到 \(k\) 即可。
时间复杂度 \(O(\Delta\dfrac{n}{L} \log L)\),\(\Delta\) 表示二分次数。
理论上取 \(L=O(\sqrt{n} \log n)\) 较优,时间复杂度约为 \(O(n \sqrt{n}\log n)\)。
卡常技巧:根据块内最值求出二分上下界,能带来较大常数优化。
被神 \(\color{black}\text{l}\color{red}\text{gvc}\) 多一个 \(\log\) 的快速排序干爆了。
P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II
题意:区间逆序对数。
莫二离的本质:\(O(n \sqrt{m} \Delta) \rightarrow O(n \sqrt{m}+n \Delta)\),\(\Delta\) 为单次挪动指针的复杂度。
适用范围:\(\Delta > O(1)\),一个数的对区间的贡献与区间中的数有关,贡献可差分。
设 \(f(x,l,r)\) 为 \(a_x\) 对区间 \([l,r]\) 的贡献,\(F(x,l)=f(x,1,l)\)。(区间转化为前缀差分)
在右指针移动到 \(x\) 时,会产生的答案变动为 \(f(x,l,x-1)=F(x,x-1)-F(x,l-1)\);
在左指针移动到 \(x\) 时,会产生的答案变动为 \(f(x,x+1,r)=F(x,r)-F(x,x)\)。
\(F(x,x-1),F(x,x)\) 可预处理;由于莫队指针移动的连续性,可以将连续的 \(-F(x,l-1)\) 和 \(F(x,r)\) 记录在区间中,二次计算。(也就是二次离线)
而指针的移动对后续询问都有贡献,因此求前缀和后才是真正的答案。
由于二次计算需要 \(O(\sqrt{n})\) 插入,\(O(1)\) 查询,离散化后使用值域分块即可。
时间复杂度 \(O(n \sqrt{n}+n \sqrt{m})\)。
略微卡常,调一下块长就能过。
P5072 [Ynoi2015] 盼君勿忘
题意:区间中所有子序列分别去重后的和取模。
~~吐槽:真的有黑吗???不过一个下位中位紫的莫队+光速幂科技。~
静态查询想到莫队。对于一个数 \(x\),它在区间 \([l,r]\) 中出现了 \(y\) 次,则其贡献为 \((2^{r-l+1}-2^{r-l+1-y}) \times x\)。
对于出现次数建立链表,并维护所有出现次数相同的数之和。(unordered_set亦可代替链表,稍慢)
考虑省去计算2的幂的 \(\log\),使用光速幂即可。
总时间复杂度 \(O(n\sqrt{n})\)。(似乎有一个点较为卡常?删去一个不必要取模后加速0.4s有余。)
P5355 [Ynoi2017] 由乃的玉米田
弱化版:link
题意:区间查询是否存在两个数加,减,乘或除为 \(x\)。
前三种操作使用莫队+两个 \(\text{bitset}\) 维护,下称 \(b_1,b_2\)。若一个数 \(x\) 出现在区间中,则 \(b_1[x]=1,b_2[R-x]=1\)。(此题中值域 \(R=10^5\))
-
加:存在 \(p,q\),使得 \(p+q=x\),变形得 \(p+R-x=R-q\),即 \(b_1[p+R-x] \ \text{and}\ b_2[q]=1\)。
-
减:存在 \(p,q\),使得 \(p-q=x\),变形得 \(p=q+x\),即 \(b_1[p] \ \text{and}\ b_1[q+x]=1\)。
-
乘:暴力枚举每一对 \(x\) 的约数并查询其是否都存在。
前三种操作时间复杂度为 \(O(\dfrac{n^2}{w})\)。
接下来考虑除法。
-
对于 \(x \geq \sqrt{R}\):暴力枚举 \(1\) 到 \(\frac{R}{x}\) 的所有数,查询其是否存在即可。
-
对于 \(x< \sqrt{R}\):单独处理,对于每一个 \(x\) 进行枚举,并令 \(i\) 从 \(1\) 扫到 \(n\):\(L[i]\) 表示最大的 \(l\) 使得 \(l\) 到 \(p\) 中存在一对商为 \(x\) 的数。对于区间问询 \(l,r\),若 \(l \leq L[r]\),则存在。
感觉除法的难度比前三种加起来都高。
除法时间复杂度为 \(O(n\sqrt{R})\)。
总时间复杂度 \(O(\dfrac{n^2}{w}+n\sqrt{R})\)。
P7446 [Ynoi2007] rfplca
题意:一棵有根树,区间的父节点编号减去 \(x\),查询两个点的lca。
现场听lxl讲了这题!
- 前置问题:link
考虑分块维护(1/1),\(stp[i]\) 为从 \(i\) 开始跳出块的步数,\(pos[i]\) 为从 \(i\) 跳出块后到了的位置。
修改:整块暴力重构。
- 回到原题
一眼弹飞绵羊,可以说是一个强化版。
一般来说DS题有两种:修改很复杂、问询很简单;修改很简单、问询很复杂,此题属于前者——lxl
修改看起来很离谱,整棵树的顺序都被打乱了,而问询只需要求lca。因此考虑不维护树的结构。
考虑分块维护(2/1),\(pos[i]\) 为从 \(i\) 向上跳出块后到了的位置。
- 查询
lca的过程很像重链剖分。
对于 \(u,v\) 两点:
若 \(pos[u]>pos[v]\),令 \(u \leftarrow pos[u]\);
若 \(pos[u]<pos[v]\),令 \(v \leftarrow pos[v]\);
若 \(pos[u]=pos[v]\),\(u>v\) 则令 \(u \leftarrow pos[u]\),反之则令 \(v \leftarrow pos[v]\)。
- 修改
散块暴力重构;
对于整块,由于每次修改后 \(fa\) 递减,因此修改次数 \(\ge \sqrt{n}\) 时必有 \(fa[i]=pos[i]\)。
时间复杂度 \(O(m\sqrt{n})\)。

浙公网安备 33010602011771号