Ynoi做题笔记

搬运自洛谷博客,原发表时间:2022-07-20

大致按照我感觉的难度排序。做了十四五道的样子,可以慢慢胡了。

评分标准:

技术力+思维力+代码力+卡常力

水平不够,评分暂时撤掉。

P3934 [Ynoi2016] 炸脖龙 I

题意:区间加,区间幂塔。

先考虑如何维护区间加+单点查询。很显然地,使用树状数组维护差分数组,前缀和即为该点的值。时间复杂度为 O(logn),常数较小。

使用扩展欧拉定理处理幂塔。设模数为 p,则 φ(p),φ(φ(p)),φ(φ(φ(p)))... 模数在 logp 次后减小到 1,因此递归求解幂塔,时间复杂度为 O(logp)。由于递归时需要进行树状数组的单点查询,因此总时间复杂度为 O(logplogn)

由于需要计算 φ(p),线性筛预处理 φ 数组即可。预处理复杂度为 O(p)

总时间复杂度为 O(n+p+qlogplogn)

技术力比较高一些,感觉实际难度并不大。

P5309 [Ynoi2011] 初始化

题意:将所有编号形如 y+kx 的数加上 z,区间查询。

根号分治,设临界值为 L

对于 xL 的情况,暴力修改即可。

而若 x<L ,则考虑分块,计算不完整块的前后缀和与整块的 sum 相加即可。

L=O(n),两种情况时间复杂度均为 O(n)

总时间复杂度为 O(mn)

个人认为略微卡常,临界值 L35n 时较优。

P5524 [Ynoi2012] NOIP2015 充满了希望

题意:操作:交换两点点权,区间赋值,单点查;查询:一段操作区间得到的结果之和。

维护每个位置最后一次修改的时间戳,单点查询记录当前的值,使用线段树维护;查询按右端点排序,单点查时在时间戳上加上其结果,答案即为区间和,使用树状数组维护。

时间复杂度 O(mlogn+qlogm)

P8511 [Ynoi Easy Round 2021] TEST_68

题意:一棵树,对于每个节点求其子树以外的任何两节点的最大异或和。

首先考虑整棵树,求出其最大异或和 bst,及得到该数的两点 x,y

显然非 xy 的祖先的所有节点的答案即为 bst

考虑 xy 的祖先:自顶向下,每次就增加了一定的点,分别对两条路径求最大异或和。

总时间复杂度 O(nloga)a 为值域。

P5527 [Ynoi2012] NOIP2016 人生巅峰

题意:区间修改为原数的三次方,区间查询是否存在某两个子序列的和相等。

注意到可能的子序列的数量为 2rl+11 个,而可能的和至多 mod×(rl+1) 种。由抽屉原理,rl+1>13 时,答案必为 Yuno

rl+113 时直接枚举即可,每个位置的值可以通过预处理快速得到,使用树状数组维护修改次数即可。

时间复杂度 O(mlogn+m×213×13)。可以优化,但足以通过。

P4689 [Ynoi2016] 这是我自己的发明

题意:一棵树,支持换根,求树上两点的子树内相同数的个数。

  • 前置问题:link

get(l,r,x)=get(1,r,x)get(1,l1,x)

g(i,x)=get(1,i,x)

则问询可转化为 i=1(g(r1,x)g(r2,x)g(r1,x)g(l21,x)g(l11,x)g(r2,x)+g(l11,x)g(l21,x))

拆成如上4个操作后,莫队计算即可,时间复杂度 O(nn)

  • 回到原题

不考虑换根操作,将节点投射到 dfs 序上,则子树为一段连续区间,即与P5268类似。

考虑静态处理换根:若当前根在 x 原子树内,设 tx 的原儿子中为当前根原祖先的那个(t 可与当前根重合),则 x 的当前子树为整棵树除去 t 的原子树的部分。

(此处拆为2个区间,再与 y 的区间分别产生莫队操作)

理性看待此题卡常:莫队操作数最大可达到 16×5105=8×106

取块长 L=nm,时间复杂度 O(nm)。(写法较为重要)

P5607 [Ynoi2013] 无力回天 NOI2017

题意:区间异或上 v,区间与 v 最大异或

区间操作,与炸脖龙一样的思路想到差分,转化为单点修改。维护树状数组的时间复杂度为 O(mlogn)

设差分数组 bi=aiai1,则 ai=b1b2...bi

有一个性质(这一步非常妙,查看了题解才想出来):{al,al+1,...,ar} 的线性基 = {al,bl+1,...,br} 的线性基。

感性证明:因为 {al,al+1,...,ar} 中的数都能用 {al,bl+1,...,br} 的某种异或表示出来,得证。

于是就不难想到使用线段树维护 b 数组的线性基,区间查询时求 alb[l+1,r] 即可。

总时间复杂度 O((n+m)lognlog2V),空间复杂度 O(nlogV)V 为值域)。

好像不怎么卡常。难点在于将原数组查询转换为差分数组查询的性质。

P5610 [Ynoi2013] 大学

题意:区间将 x 的倍数除以 x,区间查询

对于一个数 a,至多对其操作 d(a) 次。考虑从这个性质入手,用树状数组维护,时间复杂度为 O(nd(a)logn)

接下来考虑如何维护 x 的倍数集合。使用并查集快速查找下一个 x 倍数的位置。时间复杂度为 O(nd(a)α(n))

总时间复杂度为 O(nd(a)logn+nd(a)α(n))

个人认为较为卡常,也许是这个方法常数较大。(upd:似乎不手写内存也能过)

P5356 [Ynoi2017] 由乃打扑克

题意:区间加,区间第 k 小。

分块,块内排序。(排序后的数组最好附带一个原数组的编号)

(以下 L 表示块长)

  • 区间加

整块打 tag,散块中挑出区间内的数(有序),修改后和剩下的数归并排序得到整块的有序数组。

时间复杂度为 O(L+nL)

  • 区间第 k

散块通过归并排序为一组,一整块单独为一组。值域中二分答案,在每组中求出大于其的个数,判断加起来后是否达到 k 即可。

时间复杂度 O(ΔnLlogL)Δ 表示二分次数。

理论上取 L=O(nlogn) 较优,时间复杂度约为 O(nnlogn)

卡常技巧:根据块内最值求出二分上下界,能带来较大常数优化。

被神 lgvc 多一个 log 的快速排序干爆了。

P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

题意:区间逆序对数。

莫二离的本质:O(nmΔ)O(nm+nΔ)Δ 为单次挪动指针的复杂度。

适用范围:Δ>O(1),一个数的对区间的贡献与区间中的数有关,贡献可差分

f(x,l,r)ax 对区间 [l,r] 的贡献,F(x,l)=f(x,1,l)。(区间转化为前缀差分)

在右指针移动到 x 时,会产生的答案变动为 f(x,l,x1)=F(x,x1)F(x,l1)

在左指针移动到 x 时,会产生的答案变动为 f(x,x+1,r)=F(x,r)F(x,x)

F(x,x1),F(x,x) 可预处理;由于莫队指针移动的连续性,可以将连续的 F(x,l1)F(x,r) 记录在区间中,二次计算。(也就是二次离线)

而指针的移动对后续询问都有贡献,因此求前缀和后才是真正的答案。

由于二次计算需要 O(n) 插入,O(1) 查询,离散化后使用值域分块即可。

时间复杂度 O(nn+nm)

略微卡常,调一下块长就能过。

P5072 [Ynoi2015] 盼君勿忘

题意:区间中所有子序列分别去重后的和取模。

~~吐槽:真的有黑吗???不过一个下位中位紫的莫队+光速幂科技。~

静态查询想到莫队。对于一个数 x,它在区间 [l,r] 中出现了 y 次,则其贡献为 (2rl+12rl+1y)×x

对于出现次数建立链表,并维护所有出现次数相同的数之和。(unordered_set亦可代替链表,稍慢)

考虑省去计算2的幂的 log,使用光速幂即可。

总时间复杂度 O(nn)。(似乎有一个点较为卡常?删去一个不必要取模后加速0.4s有余。)

P5355 [Ynoi2017] 由乃的玉米田

弱化版:link

题意:区间查询是否存在两个数加,减,乘或除为 x

前三种操作使用莫队+两个 bitset 维护,下称 b1,b2。若一个数 x 出现在区间中,则 b1[x]=1,b2[Rx]=1。(此题中值域 R=105

  • 加:存在 p,q,使得 p+q=x,变形得 p+Rx=Rq,即 b1[p+Rx] and b2[q]=1

  • 减:存在 p,q,使得 pq=x,变形得 p=q+x,即 b1[p] and b1[q+x]=1

  • 乘:暴力枚举每一对 x 的约数并查询其是否都存在。

前三种操作时间复杂度为 O(n2w)

接下来考虑除法。

  • 对于 xR:暴力枚举 1Rx 的所有数,查询其是否存在即可。

  • 对于 x<R:单独处理,对于每一个 x 进行枚举,并令 i1 扫到 nL[i] 表示最大的 l 使得 lp 中存在一对商为 x 的数。对于区间问询 l,r,若 lL[r],则存在。

感觉除法的难度比前三种加起来都高。

除法时间复杂度为 O(nR)

总时间复杂度 O(n2w+nR)

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],令 upos[u]

pos[u]<pos[v],令 vpos[v]

pos[u]=pos[v]u>v 则令 upos[u],反之则令 vpos[v]

  • 修改

散块暴力重构;

对于整块,由于每次修改后 fa 递减,因此修改次数 n 时必有 fa[i]=pos[i]

时间复杂度 O(mn)

posted @   孤独的电磁场  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示