ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

近年 APIO 选做

2022-05-20 14:01:09  阅读:172  来源: 互联网

标签:连通 选做 近年 Difficulty text texttt leq siz APIO


带有极强目的性的做题(

「APIO2019」

数据结构年,但阻碍不了我降智的脚步(

「APIO2019」奇怪装置

给定一些区间,对于数 \(t\) 有 \(x=((t+\lfloor\dfrac{t}{B}\rfloor)\bmod A), y=(t\bmod B)\),求本质不同二元组 \((x,y)\) 个数。

\(\texttt{Difficulty 4}\)。

这种近乎数学方面的小技巧积累的太少了,比如说联合省选2022 的 D1T2。

这种题目果断找循环节,首先 \(y\) 一样说明两个数一个是 \(p\),一个是 \(q=p+kB\)。然后对于 \(x\) 解方程得到:

\[k(B+1)\equiv 0\pmod A \]

最小的 \(k\) 显然为 \(\dfrac{A}{\gcd(A,B+1)}\),再乘上 \(kB\) 的 \(B\),最小循环节就是 \(\dfrac{AB}{\gcd(A, B+1)}\)。

就变成了环覆盖问题,直接差分排序一遍即可。注意 \(A\times B\) 有点恐怖,但如果 \(>10^{18}\) 就不用模数了,分开讨论即可。

「APIO2019」桥梁

维护带权无向图,支持:

  • 修改一条边的权值。
  • 求从一个点出发,经过 \(\leq v\) 的边能到达的点的个数。

\(\texttt{Difficulty 2}\)。

当年之题,已成套路。

不带修直接离线并查集,有连边断边的可以套个线段树分治 + 可回退并查集。

带修就考虑操作分块,每次对于被修改的 \(\sqrt q\) 条边单独扫一遍处理。

其余只要保证每次的复杂度是 \(O(n)\) 的就行,还是挺暴力的。我的实现用到了排序还带一只 \(\log\)。

对调块长的作用大感震撼,虽然理论很不对,但 \(O(\sqrt{n\log n})\) 的块长跑的飞快,\(O(\sqrt{q})\) 则慢的离谱。

「APIO2019」路灯

一排 \(n\) 条线段连接了 \(n+1\) 个点,两个点连通当且仅当之间的线段均被点亮。

支持两种操作:

  • 取反某条线段的状态。
  • 求从 \(0\) 时刻开始到该次询问时,\((a,b)\) 有多少个时刻是连通的。

\(\texttt{Difficulty 4}\)。

感觉和 NOI Online 的 T3 是同道中人,就是偏序问题套了层大壳。

一只在想拆贡献,实际应该直接差分。

点亮和熄灭是类似的,对于线段 \(p\),都应当先找到 \(p\) 能到的最左点 \(l\),\(p+1\) 能到的最右点 \(r\)。

然后如果是点亮,那么 \((l,p),(p+1,r)\) 这个矩形加 \(t-i\),\(i\) 是当前时刻,\(t\) 是每个询问的时刻,根据询问变化。

熄灭也同理,就是 \((l,p),(p+1,r)\) 矩形减 \(t-i\)。

加上时间维是三维,每个矩形拆 \(4\) 个差分,就是经典三维偏序,直接 CDQ 即可。

极力推荐写 CDQ 题在拆完贡献后先写个暴力跑中型样例,保证拆贡献的准确性。

「APIO2020」

「APIO2020」粉刷墙壁

题意复杂。

\(\texttt{Difficulty 3}\)。

考虑处理出哪些段能被表示,然后就是简单贪心覆盖。

然后比较降智的想了一堆假剪枝,实际上直接倒着 DP,滚动数组优化一下空间,有值的每次只有 \(O(\sqrt {40000})\) 个。

「APIO2020」交换城市

给定一张无向图,多次询问 \((s,t)\),有两个点分别走 \(s\to t\) 和 \(t\to s\)。

求两个点经过的路径的单个边权最大值的最小值,使得两点不会相遇。可以在节点处等待。

\(\texttt{Difficulty 4}\)。

想到性质了,但是有点偏差。

实际上,就是从小到大加边,求两个点在同一连通块且连通块不是链的最早时刻。

然后还是可以魔改 Kruscal 重构树的过程,直接维护每个连通块变成非链的最早时刻,此时新建一个节点向连通块内的点连边。

因为需要维护集合中具体的点,所以要启发式合并并查集,同时维护链两端点的编号。

细节有点多。

「APIO2020」有趣的旅途

交互题。求 \(n\) 的排列,使得依次经过树上这些点,任意相邻两次移动距离,前一次 \(\geq\) 后一次。

可以询问:

  • \(\text{dis}(x,y)\):表示两点间距离。
  • \(\text{num}(x,y)\):表示有多少点 \(z\),满足 \(x\to z\) 的路径经过 \(y\)。

两种询问加起来 \(\leq 4n\) 次。保证每个点度数 \(\leq 3\)。

\(\texttt{Difficulty 4}\)。

大概能想到固定一个点,然后在它的三个子树中横跳。

担心的是最终有一个子树剩了巨大多儿子,另外两个子树空了。

于是直接找重心,因为重心的最大儿子的 \(\text{siz}_0\) 满足 \(\text{siz}_0\leq \text{siz}_1+\text{siz}_2+1\)。

其中取到等号的情况可以直接 \(\text{siz}_0\) 为一个子树,另外两个为一个,然后反复跳,最后跳到根,再跳到剩余的那个节点。

否则设 \(v=\text{siz}_0-(\text{siz}_1+\text{siz}_2)\)。

如果 \(v=0\) 了,那么立刻可以采取上述策略。否则每次找最大深度的,不在上一次的子树里的节点作为下一个决策点。

这样不会有问题,因为如果出了问题 \(v>0\)(只剩一棵子树了),但是 \(\Delta v\in[-1,1]\),根据上述性质 \(v\leq 0\),故总有 \(v=0\) 的时刻。

确定重心可以 \(n\) 次得到:

  • 对所有节点询问 \((1,i)\) 得到 \(\text{siz}_i\),满足 \(n-\text{siz}_i\leq \lfloor\dfrac{n}{2}\rfloor\) 的最小的 \(\text{siz}_i\) 即为重心。

然后以重心为根,\(n\) 次问遍每个点到根的距离。

距离为 \(1\) 的为直接儿子,需要确定每个点在那个儿子里。

一次询问可以确定 \(x\) 是否在某个儿子中,问了两个都不在就一定在第三个里,所以是 \(2n\) 次。

需要注意一个细节,就是 \(v=0\) 时刻的突然转换可能导致 fun tour 的丢失。

原因解释起来比较复杂,但是画几种情况大概能想到。解决方法是在 \(v=-1\) 的时候就直接当两个子树做,最后剩一个和上面处理方法一样。

不难发现细节巨大多,如果没有 LOJ 的数据下载感觉这辈子调不出来(

「APIO 2021」

六边形那题不太会,也没见着网上有题解的,估计是不可做,所以暂时放弃。

「APIO 2021」雨林跳跃

给定一排 \(n\) 个点,每个点有高度 \(h_i\)。

一个点可以跳到它右边最小的比它高的合法位置,或者它左边最大的比它高的合法位置。

多次询问 \([s_l,s_r],[t_l,t_r]\),求是否有 \(s\in[s_l,s_r],t\in[t_l,t_r]\) 且 \(s\) 能够到达 \(t\)。

如果有,还要输出最小步数。

\(\texttt{Difficulty 4}\)。

各种贪心结论拼起来。

部分分有些启发性的就是 \(s_l=s_r\) 且 \(t_l=t_r\) 或者只有后者的情况。

首先考虑起止点都是一个点,不难发现当且仅当 \(t\) 是 \([s,t]\) 中的最高点时,有 \(s\to t\) 的路径。

但是显然不一定是从 \(s\) 开始无脑往右跳。

一个显然正确的贪心策略:

  • 从 \(s\) 开始,在时刻保证 \(h_s<h_t\) 的情况下,往它能跳到的两个高度中的 \(\max\) 跳。
  • 再从当前的 \(s\) 出发,一直往右跳到 \(t\)。

跳的过程均可用倍增加速。

当起点变为一段区间时,显然贪心的选择最大的 \(h_i\) 满足 \(i\in[s_l,s_r],(\max_{k=i}^{s_l} h_k)<h_t\) 的 \(i\) 作为起点最优。

当终点变为一段区间时,对于 \(Q=5\) 的部分分可以直接枚举终点,这样就拿到了除正解外的所有部分分。

可以发现当前的策略已经很优了,所以大胆的进一步扩展结论。

对于终点,也贪心的钦定最小的 \(i\) 满足 \(i\in[t_l,t_r],h_i>(\max_{k=s_r}^{t_l-1} h_k)\) 为终点。

这样看似是正确的,所有从 \(<h_i\) 的点开始往右跳的点,第一个到终点区间的位置一定是 \(i\)。

但是前提是从 \(<h_i\) 的点开始,显然还可能从 \(>h_i\) 的点开始,一步跳到 \(i\) 后面的情况。

于是再钦定一个终点,找到它的方法为:

  • 找到 \([1,s_r]\) 中最小的 \(>h_i\) 的后缀 \(\max\) 点 \(j\)。
  • 找到 \([t_l,t_r]\) 中最小的 \(>h_j\) 的前缀 \(\max\) 点 \(k\)。
  • 如果 \(k\) 合法,则钦定 \(k\) 为终点。

因为如果从某个起点开始,最早跳到的 \(>h_i\) 的点就是 \(j\)。而从 \(j\) 开始能够一步跳到 \(k\),一定是最优的。

「APIO 2021」封闭道路

给定一棵树,有边权。

对于 \(k\in[0,n-1]\) 的每个 \(k\),求出使得所有点度数 \(\leq k\) 的删边最小代价。

\(\texttt{Difficulty 5}\)。

对于复杂度的严谨控制。

如果单次给定一个 \(k\),显然可以树形 DP。

设 \(f(u,o=0/1)\) 表示以 \(u\) 为根的子树都满足条件,\(u\) 已经删掉了 \(\text{deg}(u)-k-o\) 条边的最小边权和。

对于当前节点 \(u\),先将 \(\sum f(v,0)\) 作为决策,再将至少 \(\text{deg}(u)-k-o\) 个点变为 \(f(v,1)+w\)。

显然可以将所有 \(f(v,1)+w-f(v,0)\) 排序,负数一定选,再从小到大选。

单次 \(O(n\log n)\)。但显然不能全局 \(O(n^2 \log n)\)。

考虑对于 \(k\) 从小到大枚举求解。发现若\(\text{deg}(u)\leq k\),那么它的无需决策,可以全都不删。称这种点为无用点。

那么对于每条边 \((u,v)\),若 \(u,v\) 均无用则不用考虑,若只有 \(u\) 有用,那么只需要在 \(u\) 处考虑。

于是每次的决策形成了多个连通块,而每次遍历每个连通块的复杂度是可以接受的,因为 \(O(\sum \text{deg})=O(n)\)。

考虑每个点维护一个大根堆,把无用点的边权直接扔到另一个对应点的堆里。

每次询问的时候照样树形 DP,一个关键点是若堆的大小 \(>\text{deg}(u)-k\) 就不断弹出,因为这些点以后都不会用上。

每次的 DP 的插入和撤销均可以暴力做,都是 \(O(\sum \text{deg})\) 的复杂度。总时间复杂度 \(O(n\log n)\)。

具体实现上遇到了个大问题:

  • 我使用了 STL 的 multiset<long long> s 作为每个点的可删堆使用。

  • 我使用了类似如下语句 while(s[u].size() > lim) s[u].erase((-- s[u].end()))

    而注意到 \(\lim\) 可能为负数

  • 问题在于,size() 的默认返回值是 unsigned long 类型,所以必须强制转换 int,否则会出现任何正数都打不过 \(-1\) 的情况。

  • 一般 vector 循环枚举的时候不会有问题,因为都是在用非负数作比较。

  • 引以为戒!!!

标签:连通,选做,近年,Difficulty,text,texttt,leq,siz,APIO
来源: https://www.cnblogs.com/lpf-666/p/16292085.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有