2023.10 做题纪要 #1
2023.9.29
放假了哈哈。
然后下午去姥姥家,然后晚上看了一晚上视频,没干啥有意义事情。
2023.9.30
去姥姥家,和我表哥成功会面,然后打了会奥日,打到救猫头鹰了,看奥日和猫头鹰贴贴完了之后猫头鹰就寄了。恼了。我哥他同学亲切的送来了一份 榴 莲 蛋 糕,然后吃完了,感觉确实不太喜欢榴莲。
然后晚上回去和某只兔子(悠悠)玩了会密室逃脱模拟器,两个人网都巨卡,然后就放弃了,我就去打 CF 了。
然后成功以 1 分优势战胜了小粉兔()
SoyTony:你比小粉兔高一分,小粉兔 51 名,那你就 50 名进集训队了
2023.10.1
上午睡觉。
然后开学了,哈哈,非常开心。
下午啥都没干,看了一道题然后也没写出来。然后写了个 To-do list,希望 10 月能做完吧。
由于高一高二都没开学,我们只能去西扩食堂吃饭,西扩食堂好高级。
有人说我把链接放假期内容里面看不到,那我放外面了。10 月 To-do list
2023.10.2
喜报:我起床了。
今天是 hzoi 参加的第一场 accoders 联测,希望同学们下分愉快。
CF526G Spiders Evil Plan
还挺有趣的题,但是我菜啊!昨天下午看了一下午不会做。(甚至一开始还看错题想了半天)
首先考虑这样一件事情:显然我们选的路径的端点都是叶子。如果我们选出了 \(2k\) 个叶子作为路径的端点,那么一定存在一种方案使得这 \(2k\) 个点形成的虚树中的边全部选择了。考虑如果不是一个连通块,那么可以将不相交的两条路径更改连边顺序,一定能够相交,且这个过程一定结束,因为每次未覆盖的边数一定减少,所以一定存在方案。
那么我们现在可以只考虑选 \(2k\) 个叶子,使得虚树边权和最大。首先我们有个最朴素的想法,每次询问以 \(x\) 为根,然后贪心的选 \(2k\) 个贡献最大的。发现这实际上是将树进行了一个长链剖分,每次选最长的一个长链。由于长链的性质,容易发现从大到小选一定不会出现不连通的情况。那么直接贪心选 \(2k\) 条即可。不过这样选完之后虚树不一定会包括 \(x\),需要一定调整,我们先不考虑这么多,因为这毕竟是暴力做法。
问题在于,以每一个点为根做复杂度太高了,不能接受。发现,我们选的最长的路径一定是到直径的某一个端点,那么也就是说直径的一个端点一定存在于最后的连通块中。那么我们以这两个端点为根做一遍上面的做法即可。注意到端点一定是叶子,所以问题变成了选 \(2k-1\) 条长链,这个是容易预处理出一个前缀和作为答案的。
但是意识到这样的方案不一定包括 \(x\) 了。考虑进行一些调整,发现我们肯定是加入包含 \(x\) 的最长链,然后删去某一条链。我们肯定要让删去的链长度最小,那么如果最后被删的这条链与我们要加的这条链没有交,那么肯定是选第 \(2k-1\) 长的这条链将其删去,而有可能我们要删的是某条与要加入的长链的下半部分,把这种情况也算一下就行了。这里并不需要判断是不是只有一条链,因为就算是有多条链,删了之后不连通了,也不重要,因为这不会影响到答案。
P3642 [APIO2016] 烟火表演
咕了太长时间了,slope trick 基础练习题。
首先容易写出一个 DP,设 \(f_{u, x}\) 表示 \(u\) 子树内所有叶子都等于 \(x\) 的最小代价,那么有:
绝对值加 \(\min\),直接猜 \(f_u(x)\) 为凹函数,那么考虑 slope trick。
首先考虑每个儿子的操作,每次将这个东西加一个绝对值函数再取 \(\min\)。注意到,如果 \([0, x]\) 范围内 \(f_v(k)\) 有斜率等于 \(0\) 的位置,那么加绝对值之后新的最小值一定是这段平坡的左端点或者右端点,如果不存在斜率为 \(0\) 的地方那么最小值一定在右端点上。那么我们就可以通过简单讨论,得出:
(设 \(g_u\) 为 \(\min f_u(x)\),\(p_u, q_u\) 为斜率为 \(0\) 段的左右端点)
简单分类讨论即可得出,不再赘述。
然后把这个图像画出来,发现这个操作实际上是将这个凸函数的左半部分上移 \(w_u\),将平坡向右移 \(w_u\),然后用斜率为 \(-1\) 的直线连接两部分,右半部分全部删除,并且在右端点的位置变为斜率为 \(1\) 的直线。
考虑怎么用 slope trick 维护。首先发现右半部分的点永远不超过 \(1\) 个,且斜率并不重要,所以我们并不需要维护右边的点,我们只需要维护左边的点与平坡的两个端点即可。然后上述过程用 slope trick 简单维护一下就行了,大致就是将第一个点向右移动 \(w\) 位,然后令 \(p_u, q_u\) 加 \(w\)。
然后考虑合并,由于右边的点均只有一个,我们考虑先合并左边再依次插入右边,合并直接可并堆或者启发式合并即可,插入右边时分类讨论一下插入的点在平坡还是在左边,如果在平坡就更新平坡右端点,如果在左边那么就是将斜率 \(-1\) 的部分变为平坡了。同样容易维护。然后就做完了。
P9623 [ICPC2020 Nanjing R] Baby's First Suffix Array Problem
当时 yspm 给 SoyTony 推的,我在看 whk,然后就看了下这题,推完第一部分以为第二部分就类似做法就完了,然后后来回来看发现第二部分没法这么做)不过做法差的也不是特别大。
考虑先用整个后缀的排名来表示这个子串的排名,然后再考虑删除一个后缀后排名的变化。这样初始值就是区间内有多少点 \(rk_i\) 小于 \(rk_{k_i}\),直接做就行。
然后考虑什么情况下删除一个后缀后大小关系会发生改变。设 \(rk_i < rk_j\),那么考虑两个串的 \(\mathrm{lcp}\) 后的一个字符,一定有前者小于后者,那么如果大小关系发生改变,只能是因为后者的最后一个字符被删除,那么就一定需要满足 \(i < j, \mathrm{lcp}(i, j) \ge r_i - j + 1\)。
那么我们现在把问题分成两部分:求有多少原来 \(rk_x < rk_{k_i}\) 的 \(x\) 删除后缀后大于了它,与多少 \(rk_x > rk_{k_i}\) 的 \(x\) 删除后缀后小于了它。
第一部分相当于要求满足下面条件的 \(x\) 的个数:
考虑到 \(\mathrm{lcp}(x, y) = \min_{i \in (rk_x, rk_y]} h_i\),那么说明这个东西是存在单调性的,我们可以直接 ST 表二分找到满足条件的最小的 \(rk_x\) 的值 \(L\),那么上述条件就改写为:
然后这就是一个很直接的二维数点问题了,直接做即可。
第二部分相当于要求满足下面条件的 \(x\) 的个数:
这个条件就没有很好的单调性了,没有很简单的做法。同样注意到 \(\mathrm{lcp}\) 是在 \(rk_i\) 上的一个区间最小值,区间最小值启发我们想分治。
具体的,我们对 \(rk_i\) 进行分治,这样我们可以将上述询问拆成若干个形如,求有多少数 \(x\) 满足:
(\(v_i\) 表示 \((i, mid] / (mid, i]\) 的 \(h_i\) 最小值)
即:
发现这就是一个二维数点的形式了,那么我们直接树状数组维护就能跑了,这样套上一个分治,复杂度就是 \(O(n \log^2 n)\),可以通过此题。
2023.10.3
这里应该写一点简要的日记的,但是今天好像也没干啥事,所以摆了。
P9057 [Ynoi2004] rpfrdtzls
考虑一个比较神秘的扫描线转化:将询问与修改差分,然后对位置跑扫描线,以操作时间为下标动态维护整个序列。
这样,所有的查询操作就是在序列上的一个单点查询。
修改操作有:插入一个数,删除一个数。
正常维护一个 \(f_i\) 表示 \(i\) 时刻该序列的答案,发现这相当于将序列中小于等于 \(i\) 的前 \(\log A\) 个数拿出来(不考虑修改时 \(x=1\)),看最多能乘多少个数。
可以发现,若插入删除一个数,仅有 \(\log A\) 个 \(f_i\) 发生修改。
我们要维护 \(f_i\) 的历史版本和 \(b_i\),由于 \(f_i\) 的修改次数不多,只需要记录每个 \(f_i\) 上一次修改的时间即可,这样查询就是在求之前的版本和与到上一次修改前 \(f_i\) 的和。
实际上由于 \(f_i\) 是若干个连续段,所以我们只在左端点处维护,查询时找到前驱即可,维护历史版本和时就是维护区间加。
考虑 \(x=1\) 的处理,发现某一时刻序列一定形如 x11[x111x11x11]11x
即,除了最后一段外,每一段连续 \(1\) 都直接属于一个 \(x\),那么我们可以将 \(1\) 的贡献加到其后继 \(x\) 上。
最后一段的 \(1\) 比较烦人,我们先考虑把它特殊处理掉,把原问题改成区间 \(+1\) 或区间推平,区间求和即可。
我们令 \(c_i\) 为 \(i\) 前面的 \(1\) 的数量,那么现在转化一下:\(f_i\) 改为表示从 \(i\) 开始,选最多个数乘积不超过 \(A\),求这些数的 \((c_i + 1)\) 的和。
删除 \(x>1\) 是容易的,将左右两段的 \(c_i\) 加起来即可,但是插入比较烦人,因为并不能直接分裂。那就再拿数据结构维护一下区间内 \(1\) 的个数。
加入 \(x=1\) 和删除 \(x=1\) 都是平凡的,直接找到其属于的 \(x\) 然后修改即可。
上述操作均只会改变 \(\log A\) 个 \(f_i\),对这些 \(f_i\) 暴力双指针修改一下即可。(维护一下前驱后继就可以 \(O(\log A)\) 求出所有有变化的 \(f_i\))
每次暴力修改应该是两个 \(\log\) 的。注意到我们可以可以对每个点再维护一个 \(g_i\) 表示这个点还没有进行区间加的贡献,这样我们仅在插入删除操作的时候再修改历史版本和的数组,这样就是一个 \(\log\) 了。
这样查询的时候大概就是 \((t - tim_p + 1) f_p + g_p + b_i\)。
复杂度 \(O(n + m(\log n + \log m + \log A))\)。
P8511 [Ynoi Easy Round 2021] TEST_68
easy ynoi.
考虑找出全局异或和最大的一对点,除了这两个点到根的路径上的点外的答案就都等于这对点的异或和。剩下的只有两条到根的链上的路径的答案,而发现这样的点包含的点集是存在包含关系的,于是直接暴力加数计算即可。
AGC018D Tree and Hamilton Path
考虑哈密顿路径就是哈密顿回路减一条边,那么我们先考虑构造一个最长的哈密顿回路。
首先这有一个显然的上界 \(\sum_{i=1}^n 2 \min\{siz_i, n - siz_i\}\)。然后发现这个上界一定是可以取到的,具体考虑找到这棵树的重心,然后在子树之间进行匹配,如果有两个重心就在两个重心的边左右进行匹配。
然后考虑构造最长的哈密顿路径,删肯定删一条最小的边,那么直接找重心相连的最短的边,如果有两个重心那就选两个重心之间的边即可。贪心策略感性理解,具体证明我不会,咕了哈哈。
P6108 [Ynoi2009] rprsvq
怎么 Ynoi 还有数学题。
考虑方差等于平方期望减期望平方,考虑每个数对答案的贡献,简单推一下发现最后的答案一定是 \(\sum a_i^2\) 和 \(\sum_{i \ne j} x_i x_j\) 的线性组合,后者可以用总和平方减平方和得到,区间加区间平方和是平凡的,主要写下怎么求系数。
具体来讲,要求三个系数:
简单初等推导:
于是就做完了。
2023.10.4
本来打算打个模拟赛的,然后看完题之后发现 T1 T2 T3 傻逼题,T4 还是两天前刚做过的题。怎么每次我想打模拟赛的时候就正好碰上【数据删除】。
T1 二合一,分块板子加莫队板子,应该还卡常。
T2 显然的 \(O(n d(n))\) 做法,然后加大量卡常。应当将 DFS 序处理出来然后每次扫一遍就可以了。是不是有 \(O(n \log n)\) 做法来着,咕了。
T3 数学选修二练习题。求导,化简,三角恒等变换,然后解个二次方程就完了。
T4 就是这个博的第一道题。
“摆渡”“摆渡”,一摆一渡,摆的是自己,渡的是别人,渡人即渡己,故摆能渡天下人。xx 本来想进省队,但是每天开摆睡觉,最后为他人让出了一个省队的位置,同时自己的身体也变得更加健康。
所以我要摆了!!!
被 jjdw 折磨了三天,上午把【数据删除】研究完了,有可能得出了一个比较诡异的东西,不知道是不是重复发现。所以先不发了,jjdw 好像要拿来投公开赛。
好像一天一道题都没写,把自己砸了。
2023.10.5
好想,但却只能,哎。
早上看了眼 wsc 的游记,羡慕初中生了羡慕初中生了羡慕初中生了。我怎么已经高二了啊,大火鱼。两年前高二看我是不是也这种感觉啊。
但是还得学 whk,不然学考过不去,大火鱼。
不过不知道这几句话有什么联系就是了。
才发现距离 CSP-S 就只有两周了。
牙套刮到舌头了,疼炸了,呃呃。
CF1767F Two Subtrees
昨天看了半天没写的题,摆了半天。
首先有一个超级大弱智 \(O(n^\frac{7}{4})\) 做法,大力四维莫队,可以通过。感觉有点呃呃其实。
但是你把问题直接拍到 dfn 序列上去做是会丢失很多信息的(所有人的题解中都不约而同的出现了这一句话,感觉非常有趣),所以你考虑还是在原树上去做。考虑如果你只维护一个子树的众数怎么做?发现是可以跑 dsu on tree 的(虽然线段树合并也能做,但是没啥可拓展性),而 dsu on tree 的过程仅涉及加点与删点。发现这个过程本身就非常可以莫队了。那么考虑维护出来 dsu on tree 的操作序列,这样每个子树就是这个操作序列的一个前缀,这样子树变成了一个一维的信息,直接莫队即可,复杂度 \(O(n \sqrt{q} \log n)\)。带删除的最小众数需要上一个 \(O(1) - O(\sqrt{V})\) 的值域分块,大概就是维护每一个块内的最大值与最大值出现次数,然后先扫所有块找到编号最小的块,然后再扫块内找最小众数,修改由于众数出现次数变化量 \(O(1)\),可以直接维护。
你这左右两个端点都用 dsu on tree 太劣了啊,能不能再利用下树,把一边的 \(\log\) 去掉再平衡一下啊。一般树上莫队考虑一个端点移动 \(O(B)\) 范围,另一个端点遍历整棵树,我们一样这样来考虑。考虑根号分治,分子树大小小于等于 \(B\) 与子树大小大于 \(B\) 来考虑。如果询问中一个子树小于 \(B\),那么我们可以 dsu on tree 维护一个子树的信息,然后暴力将另外一个子树的所有点加入,这样复杂度 \(O(n \log n + qB)\)。
如果询问两个子树都大于 \(B\),那么所有小于等于 \(B\) 的子树就都没有用了。发现,把这些子树全部去掉后,剩下的树的叶子个数一定是 \(O(\frac{n}{B})\) 的(因为叶子代表之前的子树大小大于 \(B\)),那么如果把所有度数为 \(2\) 的点缩起来,总点数也是 \(O(\frac{n}{B})\) 的。而考虑到现在所有的询问点都在剩下的这个树的某条链上,所以我们仍然考虑莫队一类的做法,将剩下的 \(O(\frac{n}{B})\) 条链再进行分块。具体来说,我们考虑分出的一条链中,从链底到链顶的子树大小变化量不超过 \(B\)。这在一般的树上是难以保证分出的链数的,所以直接树分块是不可行的,而且树分块保证的是深度差而不是子树大小差,但是由于这里本来链数就很少了,于是对链再进行划分就能保证划分出的链数是 \(O(\frac{n}{B})\) 了(每条长链最多出现 \(O(1)\) 条不能划分满 \(B\) 的链,这样的链数仍然是 \(O(\frac{n}{B})\) 的,而划分满的部分当大于 \(B\) 后,下一条链的链底的子树大小是不计算的,于是可以看做是把这个点归给了上一条链,这样每条链的大小都大于 \(B\),链数显然 \(O(\frac{n}{B})\)。)于是再按照一般树上莫队做法做就可以了,复杂度 \(O(\frac{n^2 \log n}{B} + qB)\),平衡复杂度可得到 \(B = \frac{n \sqrt{\log n}}{\sqrt{q}}\),复杂度 \(O(n \sqrt{q \log n})\)。
P7212 [JOISC2020] ジョイッターで友だちをつくろう
火大,怎么永远想不到启发式合并,bitset 害人不浅。
首先分析题目给的性质,发现如果两个人互关了,那么由双向边连成的连通块会变成一个完全图,而如果一个人关注了一个团中的一个人,那么这个人就会关注这个团中的所有人。
那么考虑并查集维护每个极大团,对每个团维护其所有人,入边,出边的集合,统计答案时用入边数乘人数再加上每个团内的边就是答案。入边我们记录具体到人,出边只记录连到的团的编号。
考虑每次加边会发生什么,首先如果这条边是一个团内的那么直接忽略,否则就是从一个团向另一个团加边。如果原来 \(y \to x\) 已经有连边了,那么这两个团就会合并。同时发现,如果两个团 \(x, y\) 合并了,且存在 \(z\) 满足 \(x \to z \to y\) 或 \(y \to z \to x\),那么 \(z\) 也会和它们合并。
那么我们使用启发式合并维护这几个集合,在合并的时候容易判断是否存在这样的 \(z\),且可以将所有出边为 \(x\) 团的修改为出边为 \(y\),直接做即可。
我以为出入边的数量不确定不可以直接遍历,只能整些根号分治一类的算法,没意识到可以把这三个集合放在一起启发式合并就能直接遍历了,恼了。
P8528 [Ynoi2003] 铃原露露
考虑计算不满足条件的的点对,这样只需要将每个条件表示的矩形并起来就是答案。
对于一个点对 \((x, y)\),如果 \(a_x < a_y < a_{\mathrm{lca}(x, y)}\),那么如果 \(l \in [1, a_x], r \in [a_y, a_{\mathrm{lca}(x, y)})\) 那么就不合法,\(a_{\mathrm{lca}(x, y)} < a_x < a_y\) 同理。
那么考虑所有 \((x, \mathrm{lca}(x, y))\) 点对,并找到限制最紧的 \(y\)。考虑树上启发式合并,这样将轻子树插入的时候,用 set 维护一下,找到 \(x\) 的前驱后继,得出最紧的限制,容易发现这样的限制是 \(O(n \log n)\) 个的。
然后问题变成了,给定若干个矩形,查询矩形内这些矩形的并的面积。扫描线,维护最小值与最小值出现次数,然后上个历史求和即可。时间复杂度 \(O(n \log^2 n)\)。
also available in 3.9 听课记录。
AGC019C Fountain Walk
额。
首先发现显然经过一个喷泉距离会更短,那么肯定是经过尽可能多的喷泉,那么这相当于求一个 LIS。
观察样例三发现可能会出现必须横着经过某一个喷泉的情况,由于一行一列只有一个喷泉,所以仅有可能是因为上述过程中每一行或者每一列都有喷泉,导致最后卡到一行上必须横着经过一个喷泉,那么特判一下即可。
AGC018E Sightseeing Plan
to-do list 里一堆之前想做但是咕掉了题,呃呃。
考虑如果枚举了中间的点,两边的方案数是什么。即,一个点到一个矩形内所有点的路径方案数。
式子懒得写了,反正写出来之后发现可以上指标求和,然后进行两次上指标求和就可以得到一个四项的式子。发现这些式子等价于中间的点到四个点的方案数。那么我们直接枚举两个点是哪两个点,那么问题转化成了一点到矩形内一点再到一点。
然后考虑枚举路径进入矩形的点的位置,这样就能计算方案数了。对于中间的路径长度,我们可以差分一下,变成从入矩形的点到终点的距离减去从出矩形的点到终点的距离,然后就是直接枚举这个点是啥然后算一下即可。
2023.10.6
今日打模拟赛了,所以没更做题纪要,哈哈。【日总结】2023.10.6
没想到是 EI 出的模拟赛,呃呃了。
不过还是有一道题的。
AGC018C Coins
好像是典中典题了。建议改为:2023.10 补题纪要。
考虑先让所有人都选铜币,然后把问题转成两个币。
然后容易建费用流模型,然后模拟费用流,发现有四种情况:选金,选银,把金换银再选金,把银换金在选银。然后堆维护即可。
2023.10.7
P6782 [Ynoi2008] rplexq
首先题目要求的相当于就是 \(\sum_{i < j} x_i x_j\),这等于 \(\frac{1}{2}((\sum x_i)^2 - \sum x_i^2)\),前者是一个直接的二维数点,可以直接做,重点考虑后者,即有若干个询问 \((u, l, r)\),问 \(u\) 的每一个子树内 \([l, r]\) 的点数的平方和。
考虑根号分治,将度数 \(\le B_1\) 和度数 \(> B_1\) 的分开做。对于度数 \(\le B_1\) 的询问考虑直接暴力。此时需要维护出每个子树内 \([l, r]\) 内有多少点,随便做一下就是单次 \(O(\log n)\),那么这部分复杂度 \(O(q B_1 \log n)\)。
对于度数 \(> B_1\) 的点来说,这样的点只有 \(O(\frac{n}{B_1})\) 个。考虑对每一个点跑一遍莫队,变化量显然是可以 \(O(1)\) 维护的,那么这样复杂度看起来是一个 \(O(\frac{n^2}{B_1} \sqrt{q})\)。
但是我们再仔细分析一下,对询问再进行根号分治,考虑对一个点上询问数 \(\le B_2\) 的点和大于 \(>B_2\) 的点分开考虑,对于 \(\le B_2\) 的点,这些点的复杂度为 \(O(\frac{n^2}{B_1} \sqrt{B_2})\),而 \(> B_2\) 的点不会超过 \(O(\frac{n}{B_1B_2})\) 个,于是这些点的复杂度为 \(O(\frac{n^2}{B_1 B_2} \sqrt{q})\),经过平衡可得 \(B_2 = q^\frac{1}{3}\),即这部分复杂度为 \(O(\frac{n^2q^\frac{1}{6}}{B_1})\)。
两部分再平衡,即可得到一个总复杂度 \(O(nq^\frac{7}{12} \log^\frac{1}{2} n)\) 的做法,设 \(n, q\) 同阶则为 \(O(n^\frac{19}{12} \log^\frac{1}{2} n)\),还是比较接近 \(O(n \sqrt{n \log n})\) 的。
考虑可以将第一部分的单次 \(O(\log n)\) 再平衡一下。将所有需要的询问离线下来扫描线,使用分块 \(O(1) - O(\sqrt{n})\) 维护区间和,这样复杂度就是 \(O(n B_1 + n \sqrt{n})\)(直接默认 \(n, q\) 同阶),那么再平衡一下就得到了 \(O(n^\frac{19}{12})\) 的做法了,成功去掉了 \(\log\),好耶。不过需要注意到的是,如果直接离线空间复杂度是 \(O(n \sqrt{n})\),无法接受。不过由于询问都是子树询问,所以我们可以将上述的做法放到树上去做,就不需要离线了。大致就是树上 dfs,每次往一个子树 dfs 的时候先将当前根的所有询问全部减掉,dfs 完后在把所有询问全部加上,这样就只需要把询问挂在根上了,空间复杂度 \(O(n)\)。
【此处删除了一段假的再平衡,警惕单次询问低于 \(O(1)\) 算法】
可以拿到 88 分,大概是卡不过去的了。
考虑想办法将第二部分优化到 \(O(n \sqrt{n})\)。注意到我们不能对每个位置直接跑莫队的原因是每次跑的复杂度均为 \(O(n \sqrt{q})\),如果能够将每次跑的复杂度的 \(O(\sum n_i) = O(n)\) 就可以做到总复杂度 \(O(n \sqrt{q})\) 了,也就是说,每次跑莫队所访问到的节点不能重复。
那么考虑每次跑莫队的时候,如果有一个子树内已经跑过一个莫队了,那么就不考虑这个子树,仅对没有询问的子树跑莫队,莫队的时候将可能被访问到的节点拿出来离散化一下,这样莫队就是 \(O(n \sqrt{q})\) 了。对于存在跑过莫队的这些节点,注意到这些节点一定有度数 \(> B_1\),那么这样的子树不会超过 \(O(\frac{n}{B_1})\) 个,那么这样的点最多也只会增加 \(O(\frac{n}{B_1})\),取 \(B_1 = \sqrt{n}\) 就发现这部分与第一部分复杂度一致了,于是这样复杂度就变成了优秀的 \(O(n \sqrt{n})\),比上面得出的算法少个 \(O(n^\frac{1}{12})\),但是上面那个就是过不去,lxl 毒瘤。
那么实际上直接取前 \(O(\sqrt{n})\) 大的子树跑算法一,剩下的跑莫队就是对的。
CF924F Minimal Subset Difference
全身心抵触写这道题,最终还是写了。
然后感觉快写自闭了,搜状态加卡时间卡空间,这是什么阴间玩意。
题解已经写过了所以不写了,直接扔个链接。
2023.10.8
这里本来应该是有一个 Ynoi Easy Round 的,但是天天数据结构感觉要爆炸了,所以咕掉了。
而且晚上 CF Div1 + ARC 联排,感觉会很累,所以上午做点简单轻松的东西(确信)。
P9067 [Ynoi Easy Round 2022] 虚空处刑 TEST_105
代码还没写,先把题解放这,反正题很简单。
树上同色连通块经典的考虑用连通块深度最小的点来代表,这样每个连通块相连的别的连通块分为它的父亲与其它节点向它连。考虑并查集维护,并在每个同色连通块内维护所有下方连向这个连通块的点的颜色。当修改这个点的颜色时,我们首先判断是否存在下方与它相连的连通块,然后将其父亲的连通块的信息进行修改,如果存在颜色相同则并查集合并。
现在问题是如何维护,考虑以颜色为下标建动态开点线段树,每个点的叶子处维护一个链表,这样合并时进行线段树合并,复杂度就是 \(O(n \log n)\) 的。考虑修改颜色的时候,修改时需要将父亲所在连通块进行修改,但是链表是不容易进行删除的。不过实际上我们并不需要去删除,只需要再另一个位置直接插入即可,查询的时候直接将整个链表的元素全部遍历一遍,如果颜色相同则合并,颜色不同则删除,均摊复杂度仍然是对的。
CF446E DZY Loves Bridges
其实不是特别的难,只是需要一定的观察与耐心。
首先容易将题意转化成求一个 \(2^m \times 2^m\) 的矩阵的 \(t\) 次方,答案是一个 \(2^m\) 的向量与其相乘得到的向量。
重点观察这个矩阵,考虑将较小的情况写出来,发现这个矩阵实际上是一个循环矩阵。
然后关于循环矩阵有一些性质:循环矩阵的乘积仍然是循环矩阵,且循环矩阵的乘法可以表示成一个关于矩阵 \(J\) 的多项式,其中 \(J\) 为:
容易发现这个矩阵类似于一个置换,于是发现这个矩阵 \(J\) 的 \(k\) 次方就是循环矩阵中第 \(k\) 个循环。而发现这个 \(J\) 的多项式乘法与多项式循环卷积是一致的,所以我们可以按照多项式的卷积来考虑这个矩阵的乘积。(实际上你直接通过矩阵乘法的定义式也能得出这个结论,只是我觉得上述这个结论看起来挺有趣的所以写在这里了,关于这个还有很多东西,可以看这个。)
拿 \(D\) 简单算一下,可以发现一个有趣的事情:对于 \(D\) 中原来相等的数(把对角线的数看做与其它数不同的数),\(D^k\) 中仍然相等。
也就是说,这样的一个矩阵 \(D^k\) 实际上可以直接用 \(m+1\) 个整数来表示。而这个数的数量就减少了很多了,这样我们只考虑这 \(m+1\) 个整数的变化即可。
用 \([c, b_1, b_2, \cdots, b_m]\) 来表示对角线与 \(\mathrm{lowbit} = 2^{k-1}\) 处的值。容易猜到,每乘一个矩阵,对这个向量的变换同样也是一个线性变换,我们只需要找到这个变换是什么即可。
而根据循环矩阵乘积的性质,直接考虑通过卷积的式子写出表达式,那么进行一次矩阵乘法后,应当有:
直接暴力计算系数即可,这部分复杂度 \(O(m 2^m)\)。然后我们得到了转移矩阵之后,直接矩阵快速幂就能得到最后的矩阵 \(D\) 了。
最后一部分是计算答案,同样写出卷积式子:
考虑枚举 \(\mathrm{lowbit}\),那么就有:
注意到,后者的 \(i \times 2^k\) 取遍了所有值,那么也就是说后面的式子只有 \(2^k\) 种不同的值,即所有 \(i \bmod 2^k = w\) 的 \(a_i\) 的和 \(s_w\),那么我们只需要处理出这些值即可。可以直接暴力计算,也可以递推求这部分答案,前者复杂度 \(O(m 2^m)\),后者复杂度 \(O(2^m)\),不过由于 \(O(m 2^m)\) 本来就很大了,这部分暴力计算可能无法通过,所以递推一下即可。
常数很小,于是可以卡过去。
正解是这样的:仍然考虑矩阵 \(D\),发现这个矩阵是可以递归构造的。
设 \(D_i\) 为 \(2^i \times 2^i\) 的矩阵,容易发现这个矩阵可以由以下递推式导出:
可以通过小规模找规律与归纳证明,对于任意一个常数 \(r\),有:
假设 \(\alpha_1, \alpha_2\) 为两个 \(1 \times n\) 的横向量,那么暴力展开:
可以得到一个式子,考虑一般化一下,然后考虑求 \(\begin{bmatrix}\alpha_1 & \alpha_2\end{bmatrix} (p D_{k} + q I)^t\) 再带入这个式子,就可以得到一个递归求解的式子了。(式子太长了我不想打了,反正我也没写这种做法)
然后就是复杂度 \(O(\sum 2^i) = O(2^m)\)。
2023.10.9
好耶,CF 上 GM 了,AT 上 3 Dan 了!
然后上午仍然打模拟赛,所以今天大概率又没有更新。
然后模拟赛垫底了。T3 写了一场假了,T4 没看。
然后发现 T3 诈骗题,T4 弱智题。\(O(nm)\) 复杂度你 \(m \le 21\) 是个什么寄吧数据范围??
然后下午把昨天那道 Ynoi Easy Round 写了。
2023.10.10
感觉该学 whk 了!
CF1693E Outermost Maximums
好像并不是很难,反正我不会做哈哈,不过还是比较有趣的。
首先有一个显然的贪心策略:如果一个点左边小于它的最大值小于右边小于它的最大值,那么就在左边改,否则在右边改。容易发现这个条件存在一个分割点使得左边都是左边更小,右边都是右边更小,所以这种策略一定是可行的。那么直接维护这个过程就得到了一个 \(O(n^2)\) 的算法。
发现这个模拟的过程没有什么前途,因为这么做就必定需要维护每次操作之后的序列是什么,而这个序列是很难维护的。考虑将过程转置。这里有两种转置方法:
- 在值的位置计算贡献
也就是说,我们不去维护这个序列的值,也不计算每个值被修改了多少次,而是计算每个值被修改成了多少次。即,我们仅在这个数被修改成这个值的时候统计贡献。
那么考虑将每个数分为三种情况,分别是:“未确定选前缀还是后缀最大值”,“要选前缀最大值” 和 “要选后缀最大值”,我们把三种情况记作 O, L, R。
那么,当这个数第一次被加入时,状态为 O。考虑加入的每个数会对之前的数造成什么贡献。假如加入的一个数右边某一个数原来是 O,那么说明这个数一定会选后缀最大值(前缀最大值比后缀最大值要大,所以选后缀),于是将这个数变成 R。同理,若加入的一个数的左边某一个数原来是 O,那么将它变成 L。如果加入的一个数右边是 L,说明这个数就需要变成当前的这个值,那么就可以将它与当前的数看做同一类数,将它变成 O,同时将它计入答案。同样,如果加入的一个数的左边是 R,那么把它变成 O 并计入答案。
容易发现,每次进行上述的一次操作后,整个序列永远都是分成 L, O, R 三段,于是我们只需要维护这三段的两个分割点即可。每次操作计入答案的都是一个连续的区间,于是用树状数组维护区间内有多少值即可。
- 计算每个位置的贡献
我们还可以单独考虑每个位置会被修改多少次。
把问题转化一下,考虑将所有值放到数轴上,将左边的值染成黑色,把右边的值染成白色。那么我们每次变换所做的操作,就是将当前值跳到前面的第一个黑点或第一个白点,问跳到 \(0\) 的最少步数。这个东西可以用线段树维护,考虑维护每个区间若跳入时是黑/白,跳出时是黑/白的最小步数,然后合并是显然的。而每次更改位置时仅有一个位置的颜色会改变,于是直接线段树维护即可。
CF1110F Nearest Leaf
哈哈,水题。
离线,考虑换根,由于 dfs 序连续,换根后每个叶子到根的距离可以动态维护,然后做完了。
P9530 [JOISC2022] 鱼 2
算是基本上自己想出来的吧?
考虑如果存在一个区间 \([l, r]\) 满足 \(\sum_{i=l}^r < \min\{a_{l - 1}, a_{r + 1}\}\),那么这个区间内的数 \([l, r]\) 就都不能够成为最终的答案。而这样的区间只有 \(O(n \log V)\) 个,具体考虑每个点所在的区间中,如果存在上述情况,那么再拓展后区间和一定翻倍,于是最多只会有 \(O(\log V)\) 个区间。具体一点就是每次找到当前区间左右第一个大于区间和的点,然后考虑这个区间是否满足限制,然后再将区间向较小的一边拓展,容易发现这样一定能找到所有包含这个点的不合法区间。
考虑怎么查询。如果一个区间与询问区间有交,那么这个区间内的点就都不能成为答案,但是区间包含询问区间则不会造成贡献。这看起来很难处理,但是实际上如果我们不考虑这个条件的做法是找区间最小值的个数,而区间包含区间个数并不会使得这个数改变,所以仍然这么做就行了。注意左右端点需要单独处理,因为此时边界没有限制。
带修也就是简单的了,只需要将修改的点所在的区间重新求一下即可。
CF1368F Lamps on a Circle
小清新题,但是我怎么是弱智不会啊啊啊啊啊啊。
首先考虑找到答案的一个上界。发现,只要每一步操作后,没有连续的 \(k\) 个灯亮,那么灯数就会增加,这就是胜利。我们只需要考虑枚举一个 \(k\),使得最后灯亮的最多就行了。假设最后一次操作之前的灯有 \(A\) 个,那么需要满足操作完后没有连续的 \(k\) 个,这样最多有 \(n - 1 - \lfloor\frac{n - 1}{k}\rfloor\) 个,也就是 \(A + k \le n - 1 - \lfloor\frac{n - 1}{k}\rfloor\),而最后的灯数为 \(A+1\),那么就有答案为 \(\max \{n-\lfloor\frac{n-1}{k}\rfloor - k\}\)。然后构造是容易的,直接构造出最后的局面,那么每次先将对方删的全加回来,然后再把没有加入的加入几个即可。
2023.10.11
上午打模拟赛了,日总结,场上写两小时暴力大分块快写死了。
然后 whk 一会了,#1 完结,耶耶耶。
2023.10 To-do list 20/50,月底前能做完吗?