ShCPC2025胡题记录

主标题:我是fvv

传送门 https://codeforces.com/gym/105992

原本是打算vp的,但是发现自己的实现能力已经大大下降了,所以干脆就胡题吧,能写就写一点,不能写算了。

H

按照题意模拟即可。

M

思路绕了点路,但是还是回到正轨上了,算是一学期思维可达性训练的成果吧。

首先注意到可行性就是模拟二进制:先填写高位,然后让小球翻倍把填写的位往高位推一格,然而没有注意到 \(0\) 翻倍后还是 \(0\) ,因此以为翻倍的数量是按照最高位来分段的,但是这么搞就错了,而且这样没办法处理 \(x,y\),于是就考虑了一个 \(\mathcal O(n\log^2 V)\) 的 dp,即 DP\([i,j]\) 表示把前 \(i\) 个小球填好了,并且第 \(i\) 个小球使用了 \(j\) 次翻倍的最小总代价,然后就是状态 \([i,j] \rightarrow [i+1,k]\) 时只有 \(k>j\) 时才加入 \((k-j)\cdot y\) 的贡献,然后就 TLE 了。

之后转念一想,发现了 \(0\times 2 =0\) ,所以最优方案中一定存在一种方案是所有球的翻倍次数是一样的,那么直接枚举翻了几次倍,在固定了翻倍次数后只需最小化 \(+1\) 操作次数即可,这个拿贪心很容易分析出来,所以最终的时间复杂度是 \(\mathcal O(n\log V)\)

马麦批,做题做到一半杯哥又开始在群里狗叫了,烦死了

D

简单的纳什均衡分析。

I

裸的树上背包,不过注意题目给自洽这个概念的定义,然后直接模拟即可。

K

题面一坨,但是本质上还是模拟,思路上没有什么困难,大概还要写一个快速幂。

G

这辈子都不喜欢构造,做了很多的无用思考而无法理解 \(n^2+40n\)\(40\) 是怎么来的,结果竟然是 \(2500\) 以内的素数间隙,好吧,属实无聊。而且其实代数学里的构造和xcpc里的构造的风格还不太一样,太一坨了。

J

简单图论题,也是走了一点弯路,但还是弄对了。

首先由无向图的环自然的想到把边扔到 dfs 树上去分析,既然希望尽量多操作,那么就是希望每次画圈尽量做到只消除一个边,那么就是希望在消除这个边时画出来的环只有这一条边是白的其余都是黑的,然后定义一个边上的等价关系 \(R:=\set{(u,v)|如果把 u 涂黑,那么通过 u 可以把 v消除}\) 显然这是自反对称传递的,而如果一个边可以仅通过黑边消除,那么这个边的等价类都可以通过黑边消除。

而如果 \((x,y)\notin R\) ,那么就意味着如果想要把 \(x,y\) 囊括到一个环里,还需要涂黑其他的白边,这一命题在联通性上的等价条件是仅通过黑边,边 \(x,y\) 的端点不在一个连通块内,于是就可以很自然的导出做法:维护并查集,先加入黑边再加入白边,如果加入白边不影响连通块数量,那么这个白边就可以通过黑边消除,否则就把当前白边视作黑边,供后面的白边使用。至于为什么加入的顺序无关,这个的证明可以很自然的从连通块的性质导出。

A

无趣的枚举题,感觉正解不如我的 DP 解法

首先设序列 \(A\) 的长度为 \(n\) ,而元素 \(x\) 的出现次数为 \(count(x)\) ,那么通过统计每种元素对 \(g(A)\) 的贡献可以得到 \(g(A)=\sum 2^n-2^{count(x)}\),容易注意到 \(2^n-2^{count(x)}\ge 2^{n-1}\) 所以可以得出可能的 \(n\) 是非常少的,题解说是 \(\log\log x\) 级别的,可以当成常数项,也就是 \(n\sim \log x \pm \log\log x\) ,大约是 \(60\) 左右,之后题解直接枚举 \(60\) 的分拆数,然后检验即可,这是很不优美的,时间复杂度是 \(\mathcal O(\log x\cdot p(\log x))\),而拆分数 \(p(n)\sim {\exp(\pi\sqrt{2n\over 3})\over 4\sqrt 3 n}\),是亚指数级别的,劣于多项式。

我的 DP 解法也需要利用 \(g(A)=\sum 2^n-2^{count(x)}\) 这一结论,考虑 \(2^n-2^{count(x)}\) 的二进制形式,就是形如

\[(11111111000000000000000000)_2 \]

的形式,而此时容易发现 \(n\) 就是 \(1\) 的数量,那么考虑从低位往高位扫描,一旦某一项从 \(0\) 变成 \(1\) 了,那么以后都是 \(1\) 了,所以可以参考梦幻岛宝珠的优化思路,仅记录进位信息,于是有状态 \(DP[i,j,k,s]\) 表示从低位向高位扫描,扫描到第 \(i\) 位,并且前 \(i\) 位和 \(x\) 的前 \(i\) 位是相同的,第 \(i\) 位上有 \(j\)\(1\) ,然后目前前 \(i\) 位的 \(1\) 的总个数为 \(k\),并且 \(1\)\(i\) 位总共向 \(i+1\) 位进位了 \(s\) 的前提下,是否有解,显然 \(s\le 2\log x\) 而转移只需要考虑 \(j\rightarrow j'(j'\ge j)\) 即可,所以时间复杂度是 \(\mathcal O(\log^5 x)\) 的,是多项式复杂度,优于题解。

然而实际上在 \(\log x\) 十分小的时候,DP解法的计算次数还是多与枚举解法的,数据要加强

C

注意到本质上每种饺子的愉悦值函数都是一个关于吃的次数的上凸函数,而总和就是这些上凸函数的 \((\max,+)\) 卷积,仍然是一个上凸函数,所以直接 wqs 二分即可,不过有多种情况需要分类讨论,整体而言思路简单而实现十分之繁琐。

E

又一道势能线段树,看完题解算是涨知识了。
先前只知道jls线段树,并且定义节点势能为线段树节点所管的子段中不同的数的种类,而总势能的上限是 \(n\log n\) 的,而每次递归操作都会使 \(mx = se\) 从而使得势能至少减少一,所以总的复杂度有保障。注意到 \(\gcd\) 本质上也就是在质因子的指数上取 \(\min\) ,所以遂尝试迁移思路,但是最终失败了。

模仿jls线段树,对于每个线段树节点维护 lcm 和 sum ,显然一个节点不会被修改的充要条件是 lcm|x ,除此以外对于每个节点还打一个懒标记标记此节点的值是否全部相同。和jls线段树一样,首先将修改的线段打成线段树上的节点,如果懒标记存在或者不需要修改,则直接 \(\mathcal O(\log V)\) 或者 \(\mathcal O(1)\) 完成处理并退出,否则递归下去暴力修改。

递归修改的复杂度分析如下:
定义总势能为极大的存在懒标记的节点上的值的对数之和,即

\[P=\sum_{\substack{lazytag_i=1\\i的祖先均无标记}}\log(val_i) \]

显然初始化的时候总势能最多能到达 \(P=n\log V\)。对于操作一,每次至多修改 \(\log n\) 个节点,每个节点至多增加 \(\log V\) 的势能,所以所有操作一对势能的总贡献不超过 \(n\log V\log n\)。对于操作二,在递归修改的过程中,只有懒标记不存在并且至少有一个节点会被修改时才会递归下去,这意味着只要递归一次,要修改的子段内就有多一个节点要被修改,而具体的对节点的修改,则会使得节点的值 \(val_i\) 至少变成 \(val_i\over 2\) ,所以节点的势能减一,因此全体操作二的递归总次数少于总势能少于 \(n\log V\log n\) ,再加上求 \(\gcd\)\(\log\) 所以以上做法的时间复杂度时 \(\mathcal O(n\log n\log^2 V)\)

F

虹夏可爱。这是一道有趣的DP题
考虑朴素的暴力,尝试从中找到优化的思路。
如果给定了选取的元素及其顺序,如何检测是否合法?可以在按照给定顺序扫描字符串的时候,记录一个 \(0\)\(8\) 的数字 \(D\) 表示目前能找到的最长的萝莉控前缀的长度,每加入一个字符串就更新 \(D\)。这一个过程启发了一点:可以把字符串 \(i\) 抽象成一个 \(\mathbb N_9 \rightarrow \mathbb N_9\) 的映射,如果当前的 \(D\)\(j\) 则经过这个字符串之后 \(D\) 就变成了 \(link_{i,j}\)

之后将方案中能使得 \(D\) 增加的字符串成为上升串,其余称为不动串,那么显然在任何一种方案中上升串的数量不超过 \(8\),因此绝大多数都是不动串。抽象完字符串后考虑如何取消枚举的顺序,这个时候就要考虑使用动态规划了,根据前文对于字符串的抽象可以得出,一个字符串想要成为具有 \(j\rightarrow j'\) 形式的上升串需要两个条件: \(D=j\)\(link_{i,j}=j'\),具有 \(j\rightarrow j\) 形式的不动串同理:\(D=j\)\(link_{i,j}=j\),总而言之一方面是对该串本身的 \(link\) 具有一定的要求,另一方面是在 \(D\) 上升的过程中存在一个 \(D=j\) 的阶段,如是则可以把对应的串直接插入到 \(D=j\) 的那一个阶段上。相应的可以用一个长度为 \(8\)\(012\) 串来表示上述信息,第 \(i\) 位为 \(1\) 表示存在 \(D=i\) 的阶段;\(i\) 位为 \(2\) 表示暂时不存在 \(D=i\) 的阶段,但是已经存在 要求存在 \(D=i\) 的阶段的字符串了,类似于一个需求提前的操作;第 \(i\) 位为 \(0\) 则表示其余情况。于是可以考虑一个如是dp,DP\([i,s]\) 表示从前往后扫描到第 \(i\) 个字符串,并且需求信息为 \(s\) 的前提下,最大总长度是多少。至于转移则是考虑加入第 \(i+1\) 个串后枚举第 \(i+1\) 个串是具有怎样形式的串(\(j\rightarrow j'\)),其中要求 \(s\) 中第 \(j+1\) 位到第 \(j'-1\) 位之间均为 \(0\),并且将 \(s\) 中第 \(j'\) 位赋值为 \(1\) ,如果第 \(j\) 位为 \(1\) 则不改变,否则第 \(j\) 位改为 \(2\) ,因此加上处理字符串的时间复杂度,该解法的总复杂度是 \(\mathcal O(8\cdot 3^8\times n+8^3\times n)\)

UPD E 复杂度分析修正

铸币出题人,分析的东西是错的,其中错误在于:在出题人给定的势能的定义下,每递归一次并不能够保证势能一定减少一,比如只需要修改一个叶子节点的情况,实际上递归了 \(\log n\) 次才使得势能降低了一,所以这种分析方法(实际上是势能的定义)是不恰当的,以下给出修正。

对于一个线段树的节点 \(x\) ,维护以下资料

\(l(x),r(x)\) - 节点接管的区间的左右端点
\(lazytag\) - 节点接管的区间内的元素是否全都相等
\(lcm\) - 顾名思义

还是依照原题解的方案,先把线段树上所有 “自身有懒标记并且祖先没有懒标记” 的节点抽出来,令它们构成的集合为 \(\mathbb S\) ,再定义 \(\mathbb S\) 的导出集合 \(D(\mathbb S):=\) 自身或存在自己的后代节点在 \(\mathbb S\) 中的全体节点构成的集合.

当然,实际上 \(D()\) 就是把 \(\mathbb S\) 中的节点到根的路径并起来得到的点集.

之后定义线段树的总势能为

\[\sum_{x\in D(\mathbb S)} \log lcm(x) \]

对于操作一,它能增加势能最大的情况是整个序列都是 \(1\) 的情况,这个时候先依照线段树区间修改的方法,使用 \(O(\log n)\) 的时间把修改区间打散成 \(\log n\) 个节点,假设这些节点构成的集合为 \(\mathbb T\),则显然有 \(|\mathbb T|=\Theta(\log n)\),从而可以说明 \(|D(\mathbb T)|=\Theta(\log n)\),之后修改的 \(x\) 直接顶满,所以可以说明

\[\sum_{x\in D(\mathbb T)} \log lcm(x) \leq \Theta(\log n)\times \Theta(\log V) \]

而进行一次修改,不难验证对于 \(\mathbb S\) 的修改量是 \(\log n\) 级别的,所以进行一次操作一,对于势能的增量为 \(\Theta(\log x\log V)\sim \Theta(\log^2)\)

对于操作二,还是先根据线段树区间修改的方式用 \(O(\log n)\) 的时间把修改区间打散,对于打散了的节点 \(x\) ,它递归下去的充要条件是 \(lcm(x)\) 不整除 \(val\),从而说明经过修改后 \(lcm(x)\rightarrow LCM(lcm(x),val)\) 于是这样子这个节点的势能会减一,从而总复杂度会减一。
但是别忘了线段树还有 pushdown 操作,实际上进行一次标记下传操作会使得复势能增加 \(O(\log V)\) ,而不难发现区间修改只会进行 \(O(\log n)\) 次标记下传,所以这么多次操作后总的势能还是 \(O(p\log^2)\) 的,这就能说明递归次数不会爆掉。

以上应该才是正确的复杂度分析

posted @ 2025-07-23 13:27  chx#XCPC  阅读(49)  评论(0)    收藏  举报