做题笔记五
发现打 duel 的时候做题效率大幅提升,怎么回事呢。
这里还包含少量 duel 以外的做题笔记。
My Acc:\(\color{aa00aa}\textsf{tril0713}\)。
打 \(^*\) 的是看题解才会做的,当然如果你在 duel 的题目里看到打 \(^*\) 指的是 duel 结束才看的题解。
- CF1017D \(\color{aa00aa}1900\)
\(\color{aa00aa}\textsf{tril0713}\) 胜 \(\color{aa00aa}\textsf{lldxjw}\)(\(\color{aa00aa}2060+56=\color{ff8c00}2116\))
本质不同的 \(01\) 串只有 \(2^n\) 种,直接预处理出两两距离,查询二分即可。\(\mathcal O((4^n+q) \log n)\)。
- CF1080F \(\color{ff0000}2400\)
\(\color{ff8c00}\textsf{tril0713}\) 胜 \(\color{0000ff}\textsf{liangjiaqi}\)(\(\color{ff8c00}2116+9=\color{ff8c00}2125\))
唐氏 DS 题。
考虑扫描线扫描右端点,询问相当于查询 \([l,r]\) 颜色中每种颜色当前最右侧的 \(l\) 的最小值是多少。
强制在线直接上主席树即可。
写代码的时候犯唐了,可持久化的时候继承错状态了调了 10min,但是对手直接认输了,导致我还是赢了(x
- CF380B \(\color{ff0000}2400\)
\(\color{ff8c00}\textsf{tril0713}\) 胜 \(\color{808080}\textsf{yaohaoyou}\)(\(\color{ff8c00}2125+1=\color{ff8c00}2126\))
子树在每一行上都是一个区间,注意到颜色数量很少,直接枚举每种颜色的所有出现位置判断是否和子树对应行区间有交即可。复杂度 \(\mathcal O(nm)\)。
唐诗出题人给的伪代码会 MLE 掉,必须快速计算一个点的左右儿子编号。我由于数组开小报 WA,MLE 后卡常浪费大量时间,但是最后还是惊险拿下胜利。
- CF1709F \(\color{ff0000}2500\)
\(\color{ff8c00}\textsf{tril0713}\) 负 \(\color{ff0000}\textsf{Graygoo\_401}\)(\(\color{ff8c00}2126-11=\color{ff8c00}2115\))
其实不是很难的题,但是在读题和一些转移细节上浪费了太久。
用 01 trie 刻画字符串的前缀结构,设 \(f_{u,k}\) 表示 \(u\) 子树内最多可以选出 \(k\) 个串的填 \(c\) 方案数。
首先合并两个子树(这里是直接卷积),得到两棵子树恰好选出 \(k\) 个的方案数 \(f'_{u,k}\),然后考察新节点的填 \(c\):填 \(c\) 会导致 \(\forall k \in [1,c),f'_{u,k} \to f_{u,k}\) 和 \(\forall k \ge c,f'_{u,k} \to f_{u,c}\)。前缀和一下即可。
复杂度 \(\mathcal O(nm \log m)\)。
- CF476D \(\color{aa00aa}1900\)
\(\color{ff8c00}\textsf{tril0713}\) 负 \(\color{0000ff}\textsf{liangjiaqi}\)(\(\color{ff8c00}2115-110=\color{aa00aa}2005\))
离谱,这题竟然花了我 30min,然而对手 5min 秒了。
首先 \(k\) 是来搞笑的。一开始我一直在把互质往质数方向推,直到交了一发 wa 掉了。一个 pair 里三个质数不是最优的。
考虑尽可能选小的数字,不难发现一个元组里只能有 1 个偶数。考虑每个元组里都取 3 个相邻奇数,这一部分显然达到最优;然后选择一个尽可能小的和它们都互质的偶数。如何证明这样最优?
-
对于小数据可以暴力打表验证;
-
对于较大的 \(n\),由于偶数还剩很多没有使用,很容易找到和三个奇数都互质的偶数,不会造成额外开销。
-
CF121D \(\color{ff0000}2400\)
\(\color{aa00aa}\textsf{tril0713}\) 胜 \(\color{0000ff}\textsf{jjh0030}\)(\(\color{aa00aa}2005+54=\color{aa00aa}2059\))
差点又输了,哈哈。
首先需要注意到,值域内的幸运数字其实只有大概 \(5 \times 10^5\) 个,这使我们可以枚举一个端点。
二分答案 \(mid\),枚举左端点 \(l\) 即可得到右端点 \(r\)。显然不能存在长度短于 \(r-l+1\) 的区间,因此移动后 \([l,r]\) 不会包含任何区间。考虑将其它区间移动过来,对于 \(l'>l\) 的区间需要移动 \(l'-l\),对于 \(r'<r\) 的区间需要移动 \(r-r'\),双指针即可。int128。
- CF1776G \(\color{ff8c00}2100\)
\(\color{aa00aa}\textsf{tril0713}\) 胜 \(\color{0000ff}\textsf{bhbjzyh}\)(\(\color{aa00aa}2059+27=\color{aa00aa}2086\))
猜了一堆东西,最后终于是猜出来了。
结论是,选择长度为 \(n\) 的最大子段和 \([k,k+n-1]\) 一定合法。
考虑 \(l < k\) 的位置 \(l\),其第一个和等于 \(x\) 的区间右端点 \(\le r\) 且长度至少是 \(n\),\(r > k + n- 1\) 同理。这些区间就已经有 \(n\) 个。
- CF87D \(\color{ff8c00}2300\)
\(\color{aa00aa}\textsf{tril0713}\) 胜 \(\color{008000}\textsf{Gheazedrokzoe}\)(\(\color{aa00aa}2086+3=\color{aa00aa}2089\))
考虑如果 \(w_i\) 互不相同怎么做:此时可以直接按 \(w\) 从小到大合并连通块,一条边的权值即为其连接两端大小的乘积。
如果存在相同的,那么把这些连通块建树后统计每条边两端的 siz 乘积即可。
题解给出了更智慧的办法:最开始建 dfs 树,处理相同边权时按照深度合并,这样当前的 siz 就直接是子树大小。
- CF232B \(\color{aa00aa}1900\)
\(\color{aa00aa}\textsf{tril0713}\) 胜 \(\color{0000ff}\textsf{Physics212303}\)(\(\color{aa00aa}2089+24=\color{ff8c00}2113\))
注意到第 \(i\) 列选的点数和第 \(i+n\) 列相同,因此只需要 dp 前 \(i\) 列的选择点数并乘上组合数的次幂作为系数即可。
直接暴力跑背包 dp 就是 \(\mathcal O(n^4)\) 的,可过。
- CF993E \(\color{ff8c00}{2300}\)
我们只关心数字和 \(x\) 的大小关系,问题变成了 01 序列,对每个 \(s\) 求有多少子区间的和等于 \(s\)。
分治后变成卷积问题,复杂度 \(\mathcal O(n \log^2n)\)。本题前缀和单调不降,可以运用差卷积技巧做到单 \(\log\)。
- \(^*\)CF2026F \(3\color{ff0000}200\)
在线很难搞,考虑建出操作版本树然后离线 dfs。问题可以抽象成求链上背包的答案,点分治可以做到 \(\mathcal O(nv \log n)\),显然不优(虽然能过,早知道能过就赛时写了 /fn)。
我们的原问题其实远远简单于「链上背包答案」,从父亲走到儿子其实只是 push back 和 pop front,回溯则是做相反的操作:pop back 和 push front。
如果只有前两种操作,那就是经典的 baka's trick:双栈完成不删除双指针。基本操作是,维护左右两个栈 \(A,B\),push back 就给 \(B\) push,删除就给 \(A\) pop(注意 \(A\) 的栈顺序和 \(B\) 是相反的)。当 \(A\) 为空时,将 \(B\) 中元素全部倒入 \(A\) 内。查询时直接查两个栈顶即可。一个元素只会被插入一次,倒栈一次,删除一次,复杂度线性。
现在有了 pop \(B\) 和 push \(A\) 操作,如果照着上面做,在 \(B\) 空的时候需要把 \(A\) 倒入 \(B\),来回倒栈复杂度会变成 \(\mathcal O(n^2)\)。这里需要人类智慧,每次一个栈空时,把另一个栈的一半倒进来。考虑这样的复杂度:把 \(f = |size(A) - size(B)|\) 看作势能,一次操作最多使得势能增加 \(1\)。倒栈时用 \(f\) 的代价将势能清 \(0\),因此复杂度仍然是线性。
这个东西在国外好像叫「单调 deque」,可能是因为大部分时候其维护的信息是 \(\min,\max\)。反正把这东西套进来就好了,鉴定为板子题。
- CF1209G2 \(3\color{ff0000}200\)
这么水的题想了快 1h 才会也是没救了,唉。
首先考虑 G1 的 \(q = 0\) 咋做,发现如果存在 \(a_l = a_r\) 那么 \([l,r]\) 内所有元素都相等。合并相等关系后,每个连通块的答案是元素数量减去出现次数的最大值。
对每种颜色找到其第一次和最后一次出现 \(l,r\),然后并查集合并 \(\forall i \in [l,r),(i,i+1)\)。差分优化即可。
首先注意到每个连通块是一个区间,且一个颜色的每一个出现位置都在这个区间里。所有连通块的大小之和显然是 \(n\),只需要求它们的区间 \(\max\) 之和。
将一个颜色的出现次数挂到这个颜色最左边的出现位置上以方便修改。注意到所有的断点都是序列上值为 \(0\) 地方,套路的把维护 \(0\) 改成维护最小值。线段树节点维护:当前区间被覆盖次数的最小值和答案。发现合并的时候,如果两边都是最小值,需要加上中间那一段的最大值,因此额外维护节点出现次数的最大值、最左侧最右侧最小值位置、以及这个位置到区间两端的最大值。直接合并即可。
一次修改只会影响两个颜色的覆盖和端点,开 set 维护即可。复杂度 \(\mathcal O((n+q) \log n)\),但是跑的超级慢,\(2 \cdot 10^5\) 跑了 \(1.5\) 秒,难以理解。
- CF633F \(\color{ff0000}2600\)
从 \(\color{ff0000}\textsf{TheScrasse}\) 的博客找到的水题。
引理:最优解里至少一条路径的一个端点是树的直径的一端。
证明直接调整:把某条的路径的一侧改到树的直径上显然不劣。
先把树的直径拎出来,求出直径上每个点向下延伸的最大深度和子树内的直径。
最优解其实只有个两种可能:从直径两端各自引出一条路径,或者从直径一端引出一段路径,并在被包含的这一侧的某个子树内部选择了子树直径(如果在外侧则还是可以调整到全局直径)。
求一下前后缀 \(\max\) 就好了,线性。
- CF1214H \(\color{ff0000}2800\)
从 \(\color{ff0000}\textsf{TheScrasse}\) 的博客找到的水题,但是 WA 了巨多发,假了巨多次,怎么回事呢。
考虑一条长度大于 \(k\) 的链,必定有 \(col_i = col_{i+k}\),也就是链上颜色是一段长为 \(k\) 的模式串的循环拼接。
我们希望简化问题,给大部分点直接找到一条长度大于 \(k\) 的链并直接确定其颜色。距离一个点最远的点总是直径,那么先找出直径并给直径染色后,如果某个点 \(u\) 距离较远的直径端点距离大于 \(k\),则该点颜色确定。注意这个过程中可能产生无解。
我一开始以为距离直径两端都不超过 \(k\) 的点随便染就好了,但是一直 WA on 18。注意到虽然一个点可能自身到最远点距离不到 \(k\),但是它可能被某个长度大于 \(k\) 的链覆盖带来限制。简单的实现办法是直接把点的颜色和距离其较远的直径那一侧的颜色涂成相同的,因为这种颜色一定是其子树内可能有的限制。
容易证明这样填涂的合法性:如果子树内部存在大于 \(k\) 的链,那么这个子树内到直径两端一定都存在距离大于 \(k\) 的点,而这会直接导致无解(\(k \ge 3\) 时)。因此如果有解,那么子树内不会存在长度大于 \(k\) 的链,证毕。
- CF773E \(3\color{ff0000}000\)
这也能 3000?
首先容易证明最优解一定是排好序后顺次操作。
注意到 \(f\) 的值一定是先一直减 \(1\) 直到 \(a_i = -i\),然后每次令 \(f \gets \min(f+1,a_i)\)。
在权值线段树上可以很方便的找到第一个 \(a_i= -i\) 的位置,因此第一部分贡献容易计算。考虑在权值线段树上维护第二部分贡献,相当于对每个权值 \(c\) 令 \(f \gets \min(c,f+cnt_c)\),写成 \((\min,+)\) 矩乘的形式 DDP 即可。
- CF855F \(3\color{ff0000}100\)
操作只有插入没有删除,因此一个位置只会从合法变得不合法。修改一个位置的合法性只会发生 \(\mathcal O(n)\) 次。
分正负维护权值,相当于做区间取 \(\min\) 区间求和,直接上 seg beats。把不合法位置全部看作 \(0\)。
区间修改合法性不容易,但是单点修改很简单。用 set 维护不合法位置即可。
- CF436F \(3\color{ff0000}000\)
把 \(a_i\) 的贡献拆给每一个 \(p\),问题可以抽象成前缀 \(+i\),查全局 \(\max\)。
考虑分块,散块直接暴力。注意到一个块在不断整块加 \(i\) 的过程中最大值位置在单调右移,因此可以维护每一个块最大值位置的 \(\mathcal O(B)\) 个分界点,查询时直接根据整块上打的 tag 找最大值位置。
考虑怎么在 \(\mathcal O(B \operatorname{poly}(B))\) 的时间复杂度内求出一个块的所有分界点:位置 \(i\) 想成为最大值,需要满足它大于前面所有数且大于后面所有数。我们不需要管后面的条件,因为这会在求后面的位置时考虑到。也就是说,位置 \(i\) 在时刻 \(k\) 成为前缀最大值的条件是 \(\forall j \in [l,i),\dfrac{a_j - a_i}{i - j}\)。所有可能的最优解都在上凸壳上,维护凸壳后三分即可。
总复杂度 \(\mathcal O(n \sqrt n \log n)\)。
ps:发现这个东西好像叫做“分块凸包”,唯一的区别是其维护凸包找最大值使用的是类斜率优化的单调队列,而不是我这里的暴力二分 😃
- CF407E \(3\color{ff0000}100\)
我一看题,这不是我们 ABC248Ex 吗,然后发现我还没写过 ABC248Ex。但是 ABC248Ex 你咋降紫了啊???
首先考虑一个序列可以重排成 \(d(d > 0)\) 等差数列的条件:所有数字模 \(d\) 同余,不存在相同的数字,且 \(\max - \min = (r-l)d\)。那么最多加入 \(k\) 个数字的限制相当于给第二个条件放宽到了 \(\max - \min \le (r-l+k)d\)。
\(d\) 非常让人难受,不妨把原序列每一个极长的模 \(d\) 同余段拿出来单独计算。这样我们就可以把 \(a_i \gets \lfloor \dfrac{a_i}{d} \rfloor\) 了,然后条件二相当于 \(\max - \min \le r - l + k\)。
考虑序列分治,预处理 \(mid\) 向两侧扩展的 \(\max\) 和 \(\min\)。枚举左端点,右端点被分成三个区间:\(\max,\min\) 都是左边的、\(\max,\min\) 有一个是左边的、\(\max,\min\) 都是右边的。简单推倒后发现这三个限制都是二维偏序形式。对于 ABC248Ex,直接跑二维数点即可;本题由于有一维的限制是前后缀,可以直接线段树二分。
这样的总复杂度就是 \(\mathcal O(n \log^2 n)\)。
当然这个题可以和 Good Subsegment 一样做,考虑扫描线扫描右端点,维护左端点的 \(\max - \min + l\)。我们需要找到最靠左的 \(\max - \min + l \le r + k\) 的 \(l\)。考虑维护 \(\max\) 和 \(\min\) 的单调栈,弹栈的时候做区间加减即可动态维护 \(\max,\min\)。然后线段树二分的复杂度是单 \(\log\)。
- CF2032F \(\color{ff0000}2800\)
神经病题。
考虑怎么判定胜负:如果第 \(i+1 \sim m\) 这个箱子后缀的胜负已经确定,
- 如果这个后缀状态先手必胜,那么第 \(i\) 个箱子谁先没有石子可拿就会获胜(因为会直接进入后缀的游戏状态)。
- 类似的,如果这个后缀状态后手必胜,那么第 \(i\) 个箱子谁先没有石子可拿就会输掉。
第一个游戏是 Anti-Nim 游戏,而第二个游戏是普通的 Nim 游戏。Anti-Nim 游戏的胜负判定是,
- 如果序列不是全 \(1\),那么先手必胜当且仅当异或和不是 \(0\)。
- 否则,先手必胜当且仅当 \(n\) 是偶数。
考虑对这个条件计数,显然需要一个 DP。先假设 \(a_i \ge 2,a_i = 1\) 是一些无聊的分讨,死吗出题人。
设 \(f_i,g_i\) 是 \(i\) 这个后缀先手/后手必胜的划分方案数,枚举下一段的端点 \(j\)。分类讨论 \(j \sim i-1\) 这局游戏(根据 \(f,g\) 判断是 Nim 还是 Anti-Nim)的胜负后转移给对应数组。
优化转移。每个 \(f_i,g_i\) 都是给所有前缀转移,\(g_i\) 只会给前缀异或和等于 \(pre_{i-1}\) 的位置转移,而 \(f_i\) 只会给前置异或和不等于 \(pre_{i-1}\) 的位置转移。用 map 维护即可。
\(a_i = 1\) 的情况是 trivial 的。
- CF2032E \(\color{ff0000}2400\)
读错题浪费 10min,失去了 rated 首 A 和 AK。
随便手玩以下发现给所有偶数位置操作可以给两个相邻位置 \(-1\)。再加一下就可以实现给相邻两个位置 \(+1\)。
那直接从 \(1\) 到 \(n\) 扫一遍一个一个消干净就行了啊。做完了吗?真做完了。感觉还没有有的 1600 难,乐。
- CF1178G \(3\color{ff0000}000\)
首先 \(b\) 数组没有修改,不妨直接把每个点的 \(|\sum b|\) 求出来。下面的 \(b\) 指的都是求和之后的 \(|b|\)。
单点改一个 \(a\) 相当于给子树内的 \(a\) 区间加。尝试把树拍到序列上,问题变为:区间加 \(a\),区间查 \(\max \{|a_i| \cdot b_i\}\)。
考虑分块维护,散块直接暴力,对于整块加打 \(tag\),那么查整块相当于查 \(\max \{|a_i + tag| \cdot b_i\}\)。套路的拆开绝对值变为 \(\max \{\max(a_i + tag)b_i,-(a_i+tag)b_i\}\),两者都是关于 \(tag\) 的一次函数,李超树维护。
时间复杂度 \(\mathcal O(n \sqrt n \log n)\),空间复杂度 \(\mathcal O(n \log n)\),稍稍调一调块长即可通过。
- CF2036G \(\color{ff8c00}2300\)
如果 \(a \oplus b \oplus c \ne 0\),那么对于任意 \(r \ge a\),\(ask(1,r)\) 的值总是不等于 \(0\)。二分出 \(a,b\) 后直接求出 \(c\)。
否则三个数字是 \(a,b,a\oplus b\)。由于三者的异或和不等于 \(0\),我们不能再利用单调性进行二分。注意到这三个数字的最高位不可能相同,且最大值和次大值的最高位相同。枚举一个 \(r = 2^i-1\) 后 \(ask(1,r)\) 就容易找到 \(\min(a,b,c)\)。现在就有了单调性,直接二分一个、求另一个即可。
两种情况的询问次数均为 \(2 \log_2 n+\mathcal O(1)\),可以通过。
- CF185E \(3\color{ff0000}000\)
首先思考一下 \(k = 0\) 怎么做,发现曼哈顿距离和 \(\min,\max\) 三者的结合是很困难的。
这里需要一个经典 trick:曼哈顿距离转切比雪夫距离,这样很容易发现答案就是 \(\max(x_{\max} - x_{\min},y_{\max} - y_{\min})/2\) 上取整。
如果一个人要去坐地铁,那么他肯定会去最近的地铁口。不妨先求出这个距离记作 \(d_i\)。
所有坐地铁的人里我们只关心 \(d_i\) 最大的,也就是说到如果一个 \(d_i = x\) 的人去坐了地铁,那么所有 \(d_i \le x\) 的人都去坐地铁不劣(这相当于不花费任何代价删掉了一些点)。所有坐地铁的人是 \(d\) 数组的一个前缀。
考虑枚举这个前缀,问题可以抽象成,有一个人的点集 \(A\) 和地铁站点集 \(B\),需要从 \(B\) 里选择一个点 \(P\) 和汇合点 \(Q\),使得 \(\max(\max\limits_{p \in A}\{dis(p,Q)\},dis(P,Q) + d_i)\) 的值最小。
仍然转成切比雪夫距离计算,二分答案 \(mid\),首先求出 \(A\) 集合内所有矩形的交集。这是不容易的,但是发现我们只需要关心四个坐标达到极值的点的交集,这四个矩形的交集等于所有矩形的交集。然后需要判断这些矩形的交的矩形,能否和另一个地铁站的矩形相交。地铁站矩形的边长一直在变,不妨反过来做,给这个矩形的边长增加 \(mid - d_i\) 并判断矩形内是否有地铁站。主席树维护。
复杂度 \(\mathcal O(n \log^2 n)\),常数很大但是 \(6\) 秒时限下应该没啥问题。
- CF1332G \(3\color{ff0000}100\)
这题是真没啥难度啊,我也不知道为啥我想了一早上才会做。
首先手玩一下发现答案 \(\le 4\),证明不难。那么只需要分别判定答案能否是 \(3,4\)。
先考虑 \(q = 1\) 咋做。答案为 \(0\) 当且仅当原序列不增或者不降,否则取转折点附近的三个答案就至少为 \(3\)。
判断答案能否是 \(4\) 是比较难的。答案为 \(4\) 一定是两个相交的上升/下降子序列插在一起。考虑其中间的两个元素,发现这个条件等价于 \(\min(a_2,a_3) < a_1,a_4 < \max(a_2,a_3)\)。
这时候应该有一个,可能是比较自然的想法:我钦定全局 \(\min\) 去当 \(a_2\),全局 \(\max\) 去当 \(a_3\),这样只要全局 \(\max,\min\) 都不在最边上就好了。如果全局 \(\max,\min\) 在最边上,那我直接把它删掉然后继续判断,直到 \(\max,\min\) 都不在边上,或者元素被删空。
很容易发现上面说的其实就是,判断是否存在一个子区间使得 \(\min,\max\) 不在边上。容易证明这个条件是充要的:充分性显然;必要性留给读者当作练习考虑调整法,把 \(a_2,a_3\) 直接调到 \([i_1,i_4]\) 的区间 \(\min,\max\) 即可。
用单调栈刻画这个条件:设 \(l_{1,i},r_{1,i}\) 是左右第一个大于 \(a_i\) 的位置,\(l_{2,i},r_{2,i}\) 是小于,区间 \(\min,\max\) 不在边上,等价于 \(\max(r_{1,L},r_{2,L}) < R\) 且 \(\min(l_{1,R},l_{2,R}) > L\)。注意我们没有必要区分 \(l_{1,2},r_{1,2}\),只需要关注他们的 \(\min,\max\)。以下记 \(r_i = \max(r_{1,i},r_{2,i})\),\(l_i\) 同理。
考虑扫描线,扫描右端点 \(r\)。对于同一个 \(r\) 可能会有多个合法的 \(l\),但是我们只需要关注那个最大的,因为更小的 \(l\) 一定没用,这是经典的支配点对思想。那么线段树二分求出 \(l\) 即可,时间复杂度 \(\mathcal O(n \log n)\)。
做完后再看一遍发现中间几乎没有任何难点(钦定 \(\min,\max\) 一步可能有些跳跃?这一步我想了比较久),是一道高质量普及组题!
- CF418E \(3\color{ff0000}100\)
打个表发现,\(\forall i > 3,a_i = a_{i \bmod 2+2}\)。
\(a_1,a_2\) 显然是好维护的,问题是 \(a_{3,j}\) 怎么求。先求出 \(a_{2,j} = c\),发现对于所有在 \(j\) 以前出现大于等于 \(c\) 次的颜色都会恰好造成 \(1\) 的贡献,其余颜色没有贡献。
于是问题转化为,给定一个序列,单点修改,求 \([1,x]\) 这个前缀里有多少颜色的出现次数至少为 \(c\)。
这个问题看着很难做,结合 \(3.5\) 秒的时限考虑根号分治。
- 对于 \(c \ge B\),全局出现次数大于等于 \(c\) 的颜色也只有 \(\mathcal O(\dfrac{n}{B})\) 种,直接对于每一种都判断一下即可。
- 对于 \(c < B\),考虑每次修改的时候记录下一个颜色的第 \(1,2,\ldots,B\) 次出现在哪里,那么 \(c < B\) 的查询就秒了。
分析复杂度:
修改 | 查询 | |
---|---|---|
\(c \le B\) | \(\mathcal O(B \log B)\) | \(\mathcal O(\log n)\) |
\(c > B\) | \(\mathcal O(B \log B)\) | \(\mathcal O(\dfrac{n}{B} \log n)\) |
可以用分块平衡复杂度,但是 \(\log\) 的常数都比较小,所以我猜他能过。
奇异搞笑了,阈值 \(3 \le B \le 25\) 的时候都能过,大了反而就过不了了,,,,,无敌了。
看了题解的证明,感觉挺有意思的:
- 第二行实际上是由一堆 \(1,2,\ldots,cnt_x\) 的子序列拼起来的。
- 考虑第三行的第 \(i\) 个 \(x\),其在第二行一定是 \(i\)。原因是第二行小于 \(i\) 的数字的第 \(x\) 个出现早于这个位置,大于 \(i\) 的数字晚于这个位置。进一步的,该位置应当是第 \(x\) 个 \(i\)。
- 第二行到第三行相当于做了一个求逆(第 \(x\) 个 \(i\) 变为第 \(i\) 个 \(x\)),那么求逆两次相当于啥也没干,因此第二行等于第四行。同理可得第 \(x\) 行等于第 \(x \bmod 2 + 2\) 行。
那么根据这个证明我想求 \(a_{3,i}\) 其实可以求出 \(a_{2,i} = x\) 后看一下 \(a_{2,i}\) 是第几个 \(x\),然后立刻得出 \(a_{3,i}\),发现这和我的做法其实是等价的。
- CF226C \(\color{ff0000}2400\)
\(0 \color{green}{+2} \color{black}= 2\)。
这难度真不是多了 1000?
经典结论题,斐波那契数列满足 \(\gcd(f_n,f_m) = f_{\gcd(n,m)}\)。
那问题相当于在 \([l,r]\) 内选择 \(k\) 个不同的数使得 \(\gcd\) 最大。
枚举 \(\gcd = d\),要判断 \([l,r]\) 内 \(d\) 的倍数是否达到 \(k\) 个,不难发现这个值是 \(\dfrac{r}{d} - \dfrac{l-1}{d}\),整除分块即可。
因为傻逼的 \(mod = 1\) 吃了罚时,哎。
- CF1238E \(\color{ff8c00}2200\)
\(2 \color{green}{+2} \color{black}= 4\)。
首先容易统计出 \(ct_{i,j}\) 表示文本串里从字符 \(i\) 移动到字符 \(j\) 的次数,最终代价是 \(\sum\limits_{i,j} |i-j|ct_{i,j}\)。
注意到这个形式是跟顺序有关系的,我们填数字的时候需要知道前面的顺序,这很不好。考虑把贡献拆碎,把 \(|i-j|\) 拆到每一条线段上计算,转移的时候就只需要考虑哪些元素在前面哪些元素在后面了。
\(m \le 20\) 显然在提示你状压,考虑将字符一个一个的填入,设 \(f_{mask}\) 表示当前已经填入的字符集合是 \(mask\) 的最优解,暴力 \(\mathcal O(m^2)\) 转移即可。卡卡常数就过了。
- CF375C \(\color{ff0000}2600\)
\(4 \color{green}{+8} \color{black}= 12\)。
感觉 CF1920F2 就是搬的这个题 /oh
题面已经告诉你了怎么判断点在多边形内,我们可以利用这个建图。
不妨考虑一个弱化一点的问题,只有一个关键点怎么做。我们从这个关键点往任意方向引一条射线,然后对每个格子设两个状态 \(f_{i,j,0/1}\) 表示当前边界线跨过射线奇数/偶数次的最小代价,对于跨过射线的转移就让 \(0/1\) 翻转。然后发现直接跑最短路更方便。
那本题直接把 \(0/1\) 换成 \(8\) 个物品的状态压缩就好了。
- CF722F \(\color{ff0000}2800\)
\(12 \color{green}{+5} \color{black}= 17\)。
首先枚举 \(x\) 的值,找到序列中存在 \(x\) 的行,这些行均摊只有 \(\mathcal O(nk)\) 个。
对同一个左端点右端点有单调性,双指针求解;怎么判断区间是否有解?不难发现这就是 ABC371G,维护对每个质数次幂的模即可。
这个东西不支持删除,谔谔。那就用经典的 Baka's trick 维护好了。由于 \(k\) 只有 \(40\),暴力合并的复杂度可以接受。
- CF547A \(\color{ff8c00}2200\)
\(17 + 0 \color{black}= 17\)。
注意到对一个东西操作 \(k\) 次会变成 \(x^kh+\dfrac{x^k-1}{x-1}y\),这个式子显然有长度不超过 \(m\) 的循环节 \(p\),那么所有解都可以表示成 \(k \equiv r \pmod p\),两个东西 excrt 一下就好了。
想一想都感觉难写,感觉要得 \(-1\) 分了。
复习了一下 excrt 的流程:考虑合并两个同余方程 \(x \equiv w_1 \pmod {r_1},x \equiv w_2 \pmod {r_2}\),相当于解同余方程 \(x = k_1r_1 + w_1 = k_2r_2 + w_2\),exgcd 出一组特解后调整需要 \(k_1 \gets k_1 + r_2\),而这会导致 \(x\) 的值增加 \(\operatorname{lcm}(r_1,r_2)\)(注意这里不是 \(r_1r_2\) 的原因是 exgcd 会先对方程取 \(\gcd\))。
- AT_keyence2019_e Connecting Cities \(\color{ff0000}2621\)
\(17 \color{green}{+8} \color{black}= 25\)。
这不是我们 Tree MST 的序列版本吗,太经典了啊。
经典结论:若有 \(k\) 个边集 \(S_1,S_2,\ldots,S_k\) 使得这些边集的并集恰好为原图的边集,则对每一个边集求 MST 后再求 MST 得到的是原图的 MST。
考虑序列分治,每次只考虑 \([l,r]\) 内跨过 \(mid\) 的边构成的边集。这样的第一个好处就是绝对值被干掉了,一条边 \((x,y)\) 的权值可以直接表示成 \(v_x + v_y\)。
考察这些边的 MST 的形态,根据 Kruskal 的贪心,发现一个左部点连接的一定是右边 \(v_y\) 最小的点,右部点同理。因此一次分治只会产生 \(r-l+1\) 条边,将这些边全部放在一起跑一个 MST 即可。\(\mathcal O(n \log^2 n)\)。
- AT_tdpc_graph グラフ \(3\color{ff0000}304\)
\(25 \color{green}{+8} \color{black}= 33\)。
远古题的评分还是太抽象了。
首先一个 SCC 内的点肯定全都走完,因此先缩点变成 DAG 上问题。问题抽象成,在 DAG 上找两条路径使得其并集包括的点尽可能多。
考虑费用流建模,拆点,连边 \((i,i+n,1,val_i),(i,i+n,1,0),(u+n,v,2,0)\),这样就保证了每个点只会在第一次经过的时候造成贡献。然后直接跑最大费用最大流即可。
- AT_tdpc_string 文字列 \(3\color{ff0000}122\)
\(33 \color{green}{+5} \color{black}= 38\)。
奇怪的条件让人考虑容斥,但我啥也没容出来 /ng
进行连续段 dp,一个连续段即为一个以后都不往里插入元素的区间。考虑如果某个 \(a_i = 1\) 其对应的决策有哪些:
- 插入在一个连续段的两侧,连续段个数不变,系数 \(2j\)。
- 合并两个连续段,连续段个数 \(-1\),系数 \((j-1)\)。
- 新开一个连续段,连续段个数 \(+1\),系数 \((j+1)\)。
上述操作全部合法,原因是在任意位置插入两侧元素都和 \(i\) 不同。
对于 \(a_i >1\) 的情况,我们考虑将所有 \(i\) 一起插入。分别枚举 \(i,j,k\) 表示有 \(i,j,k\) 个字符去做了对应的决策。这时候我们需要先合并连续段(如果先插入在两侧了可能导致无法合并),然后再进行其它操作(剩下两个互不影响)。系数是一些比较简单的组合数。
那么就做完了,复杂度 \(\mathcal O(nk^4)\),其中 \(n=26,k=10\)。注意一些神秘的实现细节,比如 \(a_1 = 0\)。
- \(^*\) AT_tdpc_concatenation 連結 \(3\color{ff0000}819\)
\(38 \color{red}{-1} \color{black}= 37\)。
很神秘的题。
字符串要求不本质不同是非常难处理的,很难记录一些状态来判断给一个串拼接上一个串后是否是本质不同的。
最核心的 idea 是直接对字符串进行 dp,将“是否能拼接”放进状态。定义 \(x\) 位置是字符串 \(s\) 的一个 分割点,当且仅当 \(s[1,x]\) 可以被拼接出来。那么最终要求的合法串即是存在分割点 \(n\) 的串。
直接设 \(dp_{n,i,j}\) 表示长为 \(n\) 的字符串,最后 \(8\) 位是 \(i\),且最后 \(8\) 位是否是分割点的状态压缩为 \(j\) 的字符串数量。转移很暴力:枚举下一位填 \(0\) 还是 \(1\),更新 \(i'\);然后看一下 \(k\) 能否和前面的字符串组成一个给定的模式串,如果可以,那么 \(k\) 会成为分割点。可以通过位运算技巧快速更新状态。
复杂度 \(\mathcal O(l2^{2|s_i|}\operatorname{poly}(n))\),可以通过。
- ABC135E Golf \(\color{ff0000}2772\)
\(37 \color{red}{-1} \color{black}= 36\)。
首先 \(k \bmod 2 = 0\) 时 \(x+y\) 的值始终是偶数,那么给定的 \(x+y\) 是奇数时肯定无解。
考虑我们先将和调整到 \((x+y) \bmod k\) 去,然后每次只加来调整到答案。
当 \(k \bmod 2 = 0\) 或 \(k \bmod 2 = 1\) 且 \((x+y) \bmod k\) 是奇数时非常简单;否则先给 \(x\) 加上 \(k\) 后再去做减法即转化为上述情况。
通过实践证明,只有在最优解是 \(2\) 的时候上述策略不是最优的。例如以下数据:输入 4 1 1
,我们会输出:
3 -1
-1 -1
1 1
而实际上再第二步就可以结束了,特判掉 \(ans = 2\) 即可 AC。
- AGC011E Increasing Numbers \(3\color{ff0000}314\)
\(36 \color{green}{+8} \color{black}= 44\)。
考虑一个贪心,每次直接挑选最大的小于等于当前数字的 Increasing Number 减掉。正确性感性理解。
怎么高效率的找?我们在考虑第 \(i\) 位时只关心第 \(i\) 位减的是 \(i\) 还是 \(i-1\),那只需要和 \(a_ia_ia_i\) 这样的数字比大小就好了,set 维护第一个非 \(a_i\) 的位置即可。如果减的是 \(i\) 那么没有影响,否则减掉的后面一定都是 \(9\),相当于减第 \(i\) 位并给后面加 \(1\),复杂度均摊正确。
- ABC128F Frog Jump \(\color{ff0000}2521\)
\(44 \color{green}{+2} \color{black}= 46\)。
什么唐题,,
观察一下选择 \(A,B\) 后走过的坐标点,发现形如 \(kA-kB\) 和 \((k+1)A-kB\)。也就是说,相当于两个从 \(A-B,A\) 开始,公差为 \(A-B\) 的等差数列。同时观察到到达 \(n\) 的那个一定是 \(A\) 开头的等差数列。
那我们不妨枚举 \(A-B\) 的值,然后根据 \(n\) 立刻得到 \(A\) 的值。注意到直接暴力累加复杂度就是调和级数,那直接暴力就好了。
- AGC015D A or...or B Problem \(\color{ff0000}2642\)
\(46 \color{green}{+8} \color{black}= 54\)。
首先有一个经典问题是,给定 \(l,r\),询问 \(\operatorname{OR}_{i=l}^r i\) 的值。这个问题的经典做法是,首先去除 \(l,r\) 的 LCP 位,然后找到最高位从 \(0 \to 1\) 的分界点,选择这两个分界点的答案即可达到 \(2^k\)。
回到原问题,考虑我们仍然去除 LCP 后找到最高位 \(0 \to 1\) 的分界点。对于分界点左边,实际上是一个 \(2\) 的某个次幂减 \(1\) 的后缀,其按位或的值不可能小于 \(l\) 也不可能大于分界点。对于分界点右边,可以看作一个 \([0,x]\) 的前缀,最大的或显然是 \(2^{\log_2x}\),再拼上左边的那个后缀或上一个最高位。简单分讨以下计算贡献即可。
- ABC134F Permutation Oddness \(\color{ff0000}2609\)
\(54 \color{green}{+8} \color{black}= 62\)。
仍然像 CF1238E 一样把 \(|p_i-i|\) 的贡献拆到每一条线段上,这样 dp 时就不需要考虑后面的一条线段到底要连到前面的哪里。
设 \(dp_{i,j,k,h}\) 表示填了 \(i\) 个数字,有 \(j\) 个 \(p_i \to i\) 的线段经过 \((i,i+1)\),有 \(k\) 个 \(i \to p_i\) 的线段经过 \((i,i+1)\) 且当前答案为 \(h\) 的排列数量。转移时考虑新填入的元素是谁指向了它和它指向了谁来更新 \(j',k'\) 的值。这样的复杂度是 \(\mathcal O(n^5)\) 的,比较难以通过(其实能过)。考察转移式子:
- 一个点向右侧连两条边,此时 \(j,k\) 都会 \(+1\)。
- 一个点向右侧连一条边,同时接受左侧向右侧的一条边,此时 \(j,k\) 都不变,乘上转移系数 \(j\)。
- 一个点向自己连边,此时 \(j,k\) 都不变。
- 一个点向左侧连两条边,此时 \(j,k\) 都会 \(-1\),乘上转移系数 \(jk\)。
不难发现 \(j,k\) 总是相等的,因此状态数可以砍掉一个 \(n\)。
感觉很多 dp 题的优化,可能把转移式子清楚的写在纸上而不是在脑子里口胡就能立刻知道怎么优化?
- \(^*\) ABC137F Polynomial Construction \(\color{ff0000}2467\)
\(62 \color{red}{-3} \color{black}= 59\)。
怎么是我不会的板子,呜呜。
学习了一下拉格朗日插值法,和如何利用拉插求出系数。
拉格朗日插值法
给定 \(n-1\) 次多项式 \(f(x)\) 的 \(n\) 个点值 \((x_i,y_i)\) 再给出 \(k\),求出 \(f(k)\) 的值。
直接给出构造:
\[f(k) = \sum \limits_{i=1}^n y_i \prod\limits_{j\ne i}\dfrac{k-x_j}{x_i - x_j} \]考虑带入 \(k = x_j\) 进行检验,发现只有 \(i = j\) 时乘法式的值为 \(1\),其余时刻由于 \(x_i - x_j\) 的存在导致整个分子的值为 \(0\)。
拉格朗日插值法求多项式系数
考虑怎么求出 \(f(k)\) 的系数,先对于每个 \(i\) 求出与 \(k\) 无关的常量 \(w_i = y_i \prod\limits_{j \ne i} \dfrac{1}{x_i - x_j}\)。不妨记 \(g(k) = \prod k - x_i\),那么 \(f(k) = \sum \limits_{i=1}^n w_i \dfrac{g(k)}{k - x_i}\)。
\(g(k)\) 可以直接暴力乘出来,而多项式除法由于分子只有一项,可以直接模拟,复杂度即为 \(\mathcal O(n^2)\)。当然如果不想写多项式除法,可以预处理前后缀的多项式乘积,但是代价是合并需要写 \(\mathcal O(n \log n)\) 的多项式乘法,可能在一些题上会被卡常,比如本题。
- CF39A C*++ Calculations \(\color{aa00aa}2000\)
\(59 \color{red}{+0} \color{black}= 59\)。
首先先把 a++
都变成 ++a
,然后这真不是直接 sort 一下就行了???
没看到系数可以等于 \(0\) 调了快 1h,这也太唐了吧。。。
- \(^*\) CF1386A Colors / P6682 [BalticOI 2020 Day1] 染色 \(\color{ff0000}2700\)
\(59 \color{red}{-3} \color{black}= 56\)。
太难了啊,从来没见过这么做的交互题。
询问次数基本就是一倍的 \(\log_2 n\),做法大概率就是倍增和二分。但是倍增和二分都很难做,原因是有“不能经过重复元素的限制”,而倍增和二分直接做,都有很大概率会经过重复元素。
我的一个想法是,以 \(mid\) 为对称轴进行询问,每次二分消耗两次询问以避免重复,尝试获得 \(67\) 分的部分分。然而这样甚至没有正确性,原因是最后剩下一个长度为 \(2\) 的答案区间时无法进行检验。
正解非常厉害。思路是,注意到 \(c = n\) 时一定需要把 \(1,n\) 问一遍,从最劣情况反推。即,把 \(c=n\) 时的询问情况反着模拟一遍,找到那个唯一的起点。注意到 \(c=n\) 时需要选择这个起点,因此大胆猜测直接从这个起点往两边交替的走就一定合法了,?
- CF809C Find a car \(\color{ff0000}2600\)
\(56 \color{green}{+5} \color{black}= 61\)。
神秘打表题,可惜因为忘了取模吃了两发,没能拿下 \(8\) 分。
直接开始打表,发现一个 \(1\sim2^n\) 的矩形是由四个 \(2^{n-1}\) 的拼起来的,其中左下方和右上方被加了 \(2^{n-1}\)。
首先拆成前缀询问,然后考虑直接暴力递归:注意到左上角的 \(2^k \times 2^k\) 矩阵贡献容易计算,剩下三部分直接递归。然后就 AC 了并且跑的飞快。双倍经验 储能表 的题解说,这样递归复杂度是 \(\mathcal O(\log n)\) 的,谔谔。
- \(^*\) AT_acl1_e Shuffle Window \(\color{ff0000}2500\)
不知道我在想什么,观察到了一些结论,但是还是不会做。
重要观察:如果任意时刻 \(x,y\) 出现在了同一个区间里,那么最终序列 \(x\) 在 \(y\) 前面的概率就是 \(1/2\)。这个其实比较好证明,因为你每一次同时包含 \(x,y\) 的 shuffle 都有 \(1/2\) 的概率让 \(x\) 跑到 \(y\) 前面,那考虑最后一次同时包含他俩的 shuffle 就行了。
有了这个观察以后就比较简单了。考察如果 \(x,y\) 不在一个区间里,不妨设 \(x\) 在 \(y\) 的左边。为了让 \(x,y\) 跑到一个区间里,那么唯一的限制是 \(x\) 进入 \(y\) 的区间以前不能被 shuffle 到序列的第一个元素去,也就是整个概率是 \(((k-1)/k)^{pos_y - pos_x}\)。
考察答案的变化量是多少,相当于枚举原序列的每一对 \(l,r\),给答案加上 \(\Delta_{l,r} p_{l,r}\)。把 \(p_{l,r}\) 在指数上的减法拆成一个除法就好,用树状数组维护。
- \(^*\) AT_acl1_f Center Rearranging \(3\color{ff0000}700\)
毫无头猪。可能是因为我和这题水平差太远了吧。
观察 1:每个数(不是每种数)只会被操作一次。
手画一些连续操作多次的情况就能发现是没有用的。
于是我们可以根据,这个数被操作的类型进行分类:它被放到了开头、结尾还是没有动过,不妨分别记作 LRM。那么不难发现 L 是一段前缀,R 是一段后缀,M 是夹在中间的区间。
数据范围很小,我们可以暴力枚举 M 的区间 \([l,r]\)。然后就有了要求 \(\forall i \in [1,l-1),p_i > p_{i+1}\) 和 \(\forall i \in [r+1,n),p_i < p_{i+1}\),其中 \(p_i\) 指的是 \(i\) 这个位置是第几次被操作的。
当然我们还需要考虑,每次操作只能移动中间的这个限制。考虑分讨每种数字的三个元素所属的类别,
- LLL 和 RRR 显然无解。
- 如果 L,R 没有同时存在,那么一定存在一个唯一的操作序列,且这个序列对 \(p\) 没有限制。
- 剩下只有 LLR,LRR 和 LMR 三种情况。
- 先考虑 LLR 的情况。如果第一次匹配了中间的 L,那么第二次必须选 R;否则如果第一次匹配 R,那么后两次必须选 L。这两种匹配方式由我们任选并增加 \(p_{l_2} < p_r\) 或 \(p_r < p_{l_2}\) 其中之一,但是他们共同限制是 \(p_r < p_{l_1}\)。LRR 和此同理。
- 考虑 LMR 的情况,我们可以选择先 L 再 R 还是先 R 再 L,根据选择会添加限制 \(p_l < p_r\) 或 \(p_r < p_l\)。
- 我们可以先跑出只保留 \(p_r < p_{l_1}\) 这类边的拓扑序,然后根据拓扑序选择剩下的边的方向。
等等,是不是忘了什么?我们忽略了剩下元素 M 部分的顺序关系。还有一个限制是,\(a\) 选择 M 的元素顺序拼接后应当和 \(b\) 的 M 区间相等。仍然分讨每种数字的三个元素类别:
- 对于除了 LMR 的所有类别,其要么不包含 M,要么选择是唯一的,只需 check 合法性。
- LMR 这个组合,最终 M 的取值根据先 R 后 L 还是先 L 后 R 可能保留 L 或 R 任意一个。因此位置关系会带来一些额外的限制,我们不能简单的根据拓扑序唯一确定。
- 考察我们的限制究竟是怎样的形式,发现我们需要给每个 LMR 确定左还是右,且如果一个选择了左可能另一个就必须要选择左或右,这其实是 2-sat。我们在判断两个 LMR 之间的关系的时候,需要考虑:连接后不能成环以及保留的 M 连接与 \(b\) 相等。
LMR 只有 \(\mathcal O(n)\) 个,故 2-sat 的复杂度不会超过 \(\mathcal O(n^2)\)。加上枚举区间的复杂度,总复杂度即为 \(\mathcal O(n^4)\)。至此这道题终于完成。
- AT_acl1_b Sum is Multiple \(\color{0000ff}1700\)
注意到题目所求式子即为 \(k(k+1) \equiv 0 \pmod {2n}\)。
显然 \(k\) 和 \(k+1\) 贡献的质因子是不同的,不妨对每个质因子分别考虑,对于每一个 \(p^c\) 都要有 \(k \bmod p^c = 0\) 或 \((k+1) \bmod p^c = 0\)。
那直接枚举一个子集 \(S\) 表示这个子集里的方程是 \(k \bmod p^c = 0\) 而子集外面的方程是 \((k+1) \bmod p^c = 0\),这是标准的 CRT,使用 atcoder::crt
即可。
- AT_acl1_c Moving Pieces \(\color{0000ff}1900\)
考虑费用流建模,对于非障碍物的格子 \((i,j)\) 向右和向下连一条流量 \(1\) 费用 \(0\) 的边。
但是怎么限制不能经过停留的棋子呢?不难发现棋子一定是一块一块的,因此限制每个点往汇点的流量均为 \(1\) 即可。
- AT_acl1_d Keep Distances \(\color{ff0000}2700\)
一开始思维卡死了,怎么想也不会优化。到了第三天换了一个思路立刻就会做了。dfs 做题真的不可取啊。
首先考虑只需要求最多选择几个数字咋做,有一个显然到不能再显然的贪心:从左到右,能选就选。可以很容易的用倍增优化到 \(\mathcal O((n+q) \log n)\)。
于是我的思路就在这里面卡死了啊,我想的是钦定元素 \(i\) 被选择,然后判断是否存在大小为 \(mx\) 的强制包含它的集合,但是这个很难进一步优化了。
找一找性质容易发现,最优解的第 \(i\) 个元素一定是原数组的一个区间,且区间两两无交(两区间交会立刻得到更有的解,矛盾)。然后又不难发现每个区间的左端点就是从 \(l\) 向后贪心的结果,右端点是 \(r\) 向前贪心的结果,四个倍增解决。
- CF643G Choosing Ads \(3\color{ff0000}200\)
终于卡过去了!不知道为啥 set 的 lower_bound 这么慢的,,
看到区间出现至少 \(p%\) 的数而 \(p \ge 20\),很难不想到随机化。随机一个数然后去查看其出现次数是否到达给定的值。
然而我们不能直接随机去估计数字的出现次数,这样在两个数字的出现次数较为接近的时候会出现问题。我们直接上 DS 维护!
修改只有区间推平,那么考虑颜色段均摊。珂朵莉树维护所有连续段,动态开点线段树维护每个颜色的出现信息。这样设随机了 \(k\) 次,复杂度就是 \(\mathcal O((n+q) \log n + nk \log n)\)。实测取 \(k = 80\) 就有比较大的通过概率了,取更大的 \(k\) 可能会 TLE。
有一些卡常,在查单点颜色的时候不要在 set 里二分,采用更加优秀的 \(\mathcal O(\sqrt n) - \mathcal O(1)\) 的分块可以大幅提升效率。
正解是扩展摩尔投票:考虑每次删除区间任意 \(k\) 个互不相同的元素,剩下的元素一定是所有可能的 \(k-\)
绝对众数。本题 \(k \le 5\),故线段树暴力维护区间的 \(k-\) 绝对众数,\(\mathcal O(k^2)\) 暴力进行合并即可。
- CF603E Pastoral Oddities \(3\color{ff0000}000\)
我们希望选择的边的最大值最小,那么贪心的选择尽量少的边。考察一个所有点度数都是奇数的图的形态,不难发现如果它存在环,我们就可以任意找一个简单环,然后删去这个环上的所有边,所以点度数的奇偶性均不变。因此首先得出结论,我们选的必然是一个森林。
考虑每个连通块,如果有奇数个点一定无解,原因是增加一条边会改变两个点的奇偶性。如果有偶数个点,类似 ABC345F 一样,可以证明一定有解。因此一张图合法的充要条件是,所有连通块的大小都是偶数。至此有显然的 \(\mathcal O(m^2 \log m)\) 做法。
注意到随着边数增加答案单调不增,考虑从后向前扫描线。考虑先去计算 \(m\) 条边的答案 \(ans\),如果存在大小为奇数的连通块则不断地加入边权为 \(ans+1\) 的所有边。注意边的生效时间是 \(i\sim n\)。该过程可以用半在线的线段树分治优化。时间复杂度 \(\mathcal O(m \log m \log n)\)。
我想了很久也不会用整体二分做这个题,但是题解里有整体二分做法,有时间学一学吧。
- CF765F Souvenirs \(3\color{ff0000}000\)
回忆了很久才设计出了一个正确的支配点对算法,哎。
首先不难发现这个题就是 P9678(做题笔记四中的题目)的序列版本。
所谓支配点对,指的就是如果 \(u \le u' \le v' \le v\) 且 \(dis(u',v') \le dis(u,v)\),那么点对 \((u,v)\) 一定没用。
考虑分治,强制区间经过 \(mid\) 转减法为加法。将所有点按照 \(dis\) 排序后,发现点 \(i\) 只会和 \(dis\) 小于等于它的点里的前驱后继连边。原因是如果 \(k < j < i\) 且 \(dis_k,dis_j \le dis_i\),那么 \((i,k)\) 一定会被 \((j,k)\) 支配。因此一个分治中心只会连出来 \(\mathcal O(len)\) 条边。
然后问题变成了给定 \(n\) 个子区间和 \(m\) 个询问区间,求每个询问区间包含的权值最小的子区间。这是经典问题,扫描线即可。
- CF1476G Minimum Difference \(3\color{ff0000}100\)
又是第一天想了很久不会结果第 \(n\) 天再看直接就会了,,NOIP 可没有给你第二天再想的机会。。。
发现这个询问及其难搞,而时限特别宽裕,那不妨直接暴力上带修莫队,这样我们就有了每个颜色在区间里的出现次数。
然而发现查询仍然很难做,很难找到一个数据结构可以支持 查询最短的和大于等于 \(k_i\) 的区间。但是注意到所有颜色的出现次数和是 \(n\),因此只有 \(\mathcal O(\sqrt n)\) 个不同的出现次数,直接把它们搞出来双指针即可。
如何找到这 \(\mathcal O(\sqrt n)\) 个出现次数?考虑每次修改的时候,如果这个颜色的新出现次数不是 \(0\) 就把它扔进 vector,然后每次查询的时候把出现次数是 \(0\) 的删掉。这样的均摊复杂度正确。
- CF1732E Location \(\color{ff0000}2900\)
原式即 \(\dfrac{ab}{\gcd(a,b)^2}\),那么考虑区间推平一段 \(a\) 后枚举 \(a\) 的因数 \(d\) 作为 \(\gcd(a,b)\),然后查询区间可以整除 \(d\) 的最小值。
考虑区间查询,查询可以分为整段和散段。整段在推平时直接记录区间答案,散段暴力计算,时间复杂度 \(\mathcal O(nd(v) \log n)\)。
- \(^*\) CF1687D Cute Number \(\color{ff0000}2900\)
注意到所有的好段是相邻完全平方数的前面一半,那么所有好段坏段都是长度是公差 \(1\) 的等差数列。
考虑枚举 \(a_1 + k\) 在哪个连续段,先让它在第 \(i\) 个好段的开头。关键性质是,注意到后面的每一个段的长度都长于 \(i\),因此 \(a_1 + k\) 从开头移到结尾时每个元素的段最多改变一次。因此的限制是,好段不能变成坏段,同时坏段必须变成好段,相当于限制了 \(k\) 的上下界。注意到 \(a_n - a_1\) 只有 \(10^6\),那么只会分布在 \(\mathcal O(\dfrac{v}{i})\) 个段里,复杂度调和级数。
- ARC187D Many Easy Optimizations \(\color{ff0000}2859\)
你们 ARC 签到题放 D 的吗,,,
最大/小化极差的套路是枚举其中一个并最大/小另一个。那么设 \(f_i\) 表示最小值为 \(i\) 时的最小最大值,显然 \(f\) 是单调不降的,且答案是 \(\min\{f_i - i\}\)。注意如果 \(i\) 并不存在于序列中也没关系,此时 \(f_i - i\) 一定不是最优解因为调大 \(i\) 一定不劣。
考虑加入一个数对 \((a,b)\),令 \(a \le b\)。那么应该有下面的变化:
因为 \(f\) 是单调的,区间取 \(\max\) 可以变为区间推平。直接上 odt 就结束了。
- ARC187C 1 Loop Bubble Sort \(\color{ff0000}2545\)
赛后花了 1.5h 才做出来,呜呜。有没有场切的大神教教是怎么快速想到统计每个 \(p'\) 的贡献,然后发现每个 \(p'\) 的贡献是 \(2^{\text{前缀最大值个数}-1}\) 的啊 /kel
首先考虑一个 \(p'\) 是可以达到的充要条件。首先需要有 \(p'_n = n\),必要性显然。充分性也显然。但是我们需要统计每个 \(p'\) 对应多少 \(p\)。
经过大量打表观察猜测可以发现一个 \(p'\) 对应 \(2^{\text{前缀最大值个数}-1}\) 个 \(p\)。
考虑 dp,设 \(f_{i,j}\) 表示填了 \(1\sim i\) 且前缀最大值是 \(j\) 的贡献和。直接 dp 是 \(\mathcal O(n^3)\) 的,前缀和优化就是 \(\mathcal O(n^2)\) 的。
一道从头套路到尾的套路题。
观察到对所有位置都操作一次相当于给所有数字 \(-3\),因此答案在模 \(3\) 意义下有单调性,即对模 \(3\) 相同的等价类答案单调。那么我们可以进行 \(3\) 次二分求解。
考虑如何 check 一个 \(x\),记 \(b_i = a_i - x\),首先要 \(b_i \ge 0\)。考虑记位置 \(i\) 操作了 \(h_i\) 次,那么不难有方程 \(2a_i + a_{(i+1) \bmod n} = h_i\)。这种问题的通用解法是根据第一个方程求出 \(h_1 = f_1h_n + g_1\),一直往后带入即可求出 \(h_n\) 的值,再往前反推即可。
注意最终 \(f\) 的系数可能达到 \(2^{n}\),但是注意到所有方程的解不会超过 \(10^9\),求这个方程在模 \(10^9+7\) 意义下的解即可。
奋战两小时拿下签到题。
首先考虑 \(a_i = 1,b_i = 2\) 怎么做,这和一般的汉诺塔问题基本相同。设 \(f(n)\) 表示子问题 \(n\) 的答案,考虑求解 \(f(n)\)。注意到 \(n\) 只能在空栈上移动,而任何东西都可以在 \(n\) 上移动,因此先把 \(n\) 移动到栈 \(2\) 位置,这需要先把 \(1 \sim n - 1\) 移动到栈 \(3\),代价是 \(2f(n-1)\),然后移动 \(n\),然后再把 \(1 \sim n -1\) 移动回来,总代价是 \(3f(n-1) + 1\),故 \(f(n) = 3f(n-1)+1\)。
回到一般情况,我们仍然从大到小的考虑元素。找到第一个 \(a_i \ne b_i\) 的位置,不难发现想要移动它 \(1 \sim i-1\) 必须叠成一个栈。因此总问题分为两个部分:求解 \(1 \sim i-1\) 合并为一个栈的代价,和求解 \(1 \sim i-1\) 这个栈拆成 \(b_i\) 的代价。
两个问题的解法基本相同,先考虑第一个问题怎么做。类似上面的,设 \(g(x,y)\) 是把 \(1 \sim x\) 堆在 \(y\) 的最小代价。考虑如果 \(x=2\),那么我们把 \(1\sim x-1\) 合成到 \(4-y\) 去,然后把 \(x\) 移到 \(y\),再把 \(4-y\) 的柱子移过来,有 \(g(x,y) = g(x-1,4-y) + 2f(x-1) + 1\)。\(x \ne 2\) 的情况是一些更复杂的分讨,但是核心想法相同。
第二个问题和第一个的唯一区别是移动和合并的顺序不同,改一下就好了。
时间复杂度显然是线性。
首先对题面做第一步转化:我们不关心最长公共子串的具体值,只关心它是否大于等于 \(k+1\)。而公共子串长度有单调性,因此我们只关心是否存在长度为 \(k+1\) 的公共子串。因此问题转化为:求有多少 \(s,t\) 满足存在公共子串 \(w\) 且不存在长度为 \(k+1\) 的公共子串。
注意到 \(2^{k+1} = 16\) 非常小,我们可以把所有的 \(2^{k+1}\) 个子串是否出现过压进状态。一开始我在想对两个串同时进行 dp,但是时空复杂度都爆炸。后来发现两个串的填充是基本独立的,我们只需要保证其最后拥有的 \(2^{k+1}\) 子串不交。
那么进行 DP,设 \(dp_{n,o,r,b}\) 表示长度为 \(n\),串的最后 \(k\) 个字符是 \(o\),串中是否存在了 \(w\) 的状态是 \(r=0/1\),串中拥有的所有 \(2^{k+1}\) 子串的状态是 \(b\) 的方案数,转移直接枚举填什么就行了,比上面那个题 连接 简单一万倍。
然后最终的问题是,求 \(\sum \limits_{i \& j = 0} f_ig_j\),这是套路的,考虑对 \(g\) 数组的下标反转(\(0111 \to 1000\)),这样限制就变成了 \(g\) 是 \(i\) 的超集,高维前缀和即可。
时间复杂度 \(\mathcal O((n2^k+2^{k+1})2^{2^{k+1}})\)。
- CF2038F Alternative Platforms \(\color{ff0000}2500\)
对两个序列的 \(\min\) 取 \(\max\) 是很难受的,因为 \(\max\) 对 \(\min\) 没有分配律。那么不难想到因为 \(\max(a,b) = a + b - \min(a,b)\),我们可以对两个序列分别求出答案后,再减去 \(\min\) 问题的答案。\(\min\) 对 \(\min\) 有分配律,因此这等价于对 \([\min(a_i,b_i)]\) 这个序列求答案。至此问题转化为单个序列。
首先给数组排序,考虑枚举集合大小 \(k\) 并枚举 \(\min\) 的值 \(j\),应当有 \(f_{k+1} = \sum \limits_{j=1}^n \dbinom{n - j}{k} a_j\)。这个式子可以卷积优化。
- CF2038I Polyathlon \(\color{ff0000}2500\)
最关键的观察是,对于一个固定的起点,考虑比较两个选手的字符串,找到第一个不同的位置,是 \(1\) 的会永远淘汰是 \(0\) 的。
因此枚举起点然后两两淘汰即可,复杂度瓶颈在于找 LCP。
比较简单的题,这题场上只过了 10 个是不是榜的问题啊??
首先记 \(s_a,s_b\) 是先后手的棋子总数,那么如果 \(s_a = s_b\) 则一定平局,否则 \(s_a > s_b\) 则先手不败,\(s_a < s_b\) 则先手不胜,因此我们要判定的其实只是先手能否胜/平。
先考虑第一种情况,我们希望先手获胜,这时候后手想要平局的唯一策略是一个棋子一直右移,让先手永远也追不上。这时候如果最右边的棋子是后手就直接结束了,否则先手需要在后手的棋子冲过最右边先手的棋子之前吃掉后手棋子。
注意到双方任意时刻都不会左移棋子,左移一定是不优秀的。考虑这么一个贪心:双方任意时刻都会选择自己最靠右侧的棋子向右移动。对于后手这个策略显然正确,因为这样移动就有更大概率可以冲出去。对于先手这个策略也比较对,因为移动右边的棋子有更大概率可以追上后手的棋子。
那么后手的棋子可以分为两部分:左半部分是放弃的,右半部分是向右移动并希望冲出去的,我们不妨枚举这个分界点在哪里,设分界点右侧有 \(x\) 个后手的棋子,那么根据上面的分析先手也只会动用前 \(x\) 个棋子去吃后手的棋。如何判断后手能不能冲出去?如果当前最右侧的棋子位置是 \(r\),那你其实只需要比较 \(\sum r - pos_a\) 和 \(\sum r - pos_b\) 的大小。这是因为一次吃棋后,我们仍然可以认为将两个棋子可以一起右移。
由于 \(\sum m_i\) 比较大,复杂度只能和 \(n\) 有关。当然这是简单的,直接双指针一下就是线性。
被诈骗了很长时间,火大!
重要观察:原图是广义串并联图。
由于边必须是直线,如果出现了同胚 \(K_4\) 的子图则必然画不开,因此原图不存在同胚 \(K_4\) 的子图,而这是判定广义串并联图的条件。
没有出现在 \(m\) 条额外边里的点一定是二度点,将它们全缩起来后点数就降到了 \(\mathcal O(m)\) 级别;缩合的新边系数可以用矩阵快速幂快速计算。
广义串并联图部分之前已经写过,在这里。
比 G 还离谱,这题应该过 100 个的啊,打这场比赛的选手是不是有点菜了???
首先每种颜色的合法性判断是独立的而且与颜色本身无关,考虑只有一种颜色该怎么做。不难发现我们一定会贪心的删去最大的,并且加入一个手牌里没有的最小牌,正确性显然。
颜色比较多的时候,问题在于可能存在一种策略使得从一个颜色里删去牌并加到另一个颜色里,这些决策是很复杂的,很难直接贪心解决,那么考虑 DP。
可能存在从后面拿牌给前面的情况,看似没法直接 DP。但是注意到,删去的牌可以插入任意颜色,即从不同颜色里删去的牌没有区别。考虑利用这个设计 DP:\(dp_{i,j}\) 表示考虑了前 \(i\) 种颜色,总共删除了 \(j\) 张牌时最少需要插入多少牌使得前 \(i\) 堆变得合法。最终 \(j\) 是合法的当且仅当 \(dp_{A,j} \le j\)。转移就是一个普通的背包。
时间复杂度 \(\mathcal O(n^2)\),可以通过本题。
- CF1601E Phys Ed Online \(\color{ff0000}2900\)
Div1 E 就这?感觉是个 Div1 B。
贪心的,每次只会在 \(l+pk\) 时刻激活票,而激活票的代价是 \(l\) 到它的 \(\min\),因此答案就是 \(\min(l \to l) + \min(l\to l + k) + \min(l \to l + 2k) + \ldots\)。
显然每个模 \(k\) 同余的类是独立的,分开计算,问题就可以转化为多次询问一个区间的前缀最小值之和。倒着扫描线维护单调栈即可。
- CF1583G Omkar and Time Travel \(\color{ff0000}3000\)
计算每个线段包含的关键线段个数 \(v_i\)。
考虑模拟这一过程,维护还没有经过的关键线段个数 \(w\)。如果当前刚刚通过时间隧道走完了一条线段,那么这条线段所有包含的线段都被清空。考虑此时的 \(w\):
- 如果 \(w \ne 0\),那么走完区间里所有线段也不可能变的合法,此时需要记录一个 \(g_i\),\(g_i\) 表示的是直接走过这个区间需要的时间。
- 否则最终的停靠点一定在这个区间内,给 \(w\) 加上包含的区间数量后直接暴力递归。
\(v_i\) 和 \(g_i\) 可以直接线段树扫描线求解,但是暴力递归的复杂度怎么分析呢?
很可惜,暴力递归的复杂度是 \(\mathcal O(n^2)\) 的,考虑区间 \(\{[1,n],[2,n-1],[3,n-2],\ldots,\}\) 就直接卡爆了!
观察我们的代码其实在干什么,是遇到一个关键区间给 \(w\) 减 \(1\),直到减到 \(0\) 后给 \(w\) 加上包含的区间数量。发现这其实等价于从最后一个区间往前一个一个扫!对于 \(l < now\) 一部分的处理可以树状数组解决。
- \(^*\) CF1621G Weighted Increasing Subsequences \(3\color{ff0000}200\)
差了几步观察。
首先考虑拆开贡献,对每个位置计算一下它被几个子序列包含。
那么不妨枚举位置 \(x\),一个合法的 \(y\) 需要满足 \(y\) 后面至少存在一个大于 \(x\) 的数字,考察这样的 \(y\) 有什么性质,首先它是一个后缀 \(\max\),因为下一个位置的后缀 \(\max\) 发生了变化。其次它是大于 \(x\) 的最后一个后缀 \(\max\)。
\(y\) 的条件显然有单调性,因此问题转化为求以 \(x\) 开头结尾小于 \(y\) 的上升子序列数量,但是这个很难。
-
性质 A:\(y\) 后面的数字全都小于 \(x\),因此答案就是 \(x\) 开头的所有上升子序列减去以 \(y\) 结尾的上升子序列。
-
性质 B:设 \(y\) 后面任意一个位置为 \(z\),则满足 \(a_z \le a_x < a_y\),因此一个后缀 \(\max\) 管辖的是一个区间,把每个区间和其对应元素分别拿出来求即可。
-
CF1535F String Distance \(3\color{ff0000}000\)
暴力直接 AC 了,哈哈。
首先注意到字符集不一样答案一定是 \(1337\),否则答案不会超过 \(2\):直接都排序一下就行了。按照每一个相同的字符集独立求解,由于串互不相同,我们只需要 check 每一个 \(i,j\) 的 \(f(i,j)\) 是 \(1\) 还是 \(2\)。
考虑什么时候答案是 \(1\),找到最左边和最右边满足 \(s_i \ne t_i\) 的下标 \(i_1,i_2\),我们排序的区间一定要包含 \(i_1,i_2\),并贪心的希望其不要包含 \(i_1,i_2\) 左边,因此排序的区间就是 \([i_1,i_2]\)。如果 \(s[i_1,i_2]\) 有一个是有序的那答案就是 \(1\)。
直接做是 \(\mathcal O(n^2 \log n)\) 的,在 \(|s_i|\) 很小的时候会 TLE,那考虑设计一个 \(|s_i|\) 比较小的时候的算法。考虑直接枚举区间 \([i_1,i_2]\) 是谁,注意这里需要要求两边相等,且这个相等段已经最长,这时候计算贡献。容斥来快速求解 \(i_1,i_2\) 两位上不能相同的限制。直接实现复杂度是 \(\mathcal O(n|s_i|^2 \log n)\) 的。
在 \(|s_i| \le 10\) 时跑算法二可以通过。
正解非常厉害,首先正解做的第一件事情是排序,这个看似没啥用的事情非常厉害:
- 对于固定的串 \(i\),和它离的越近的串 LCP 越长。
- 固定 \(l,r\) 时,如果一个区间内的串的 \([1,l-1]\) 都相等,且区间 \([l,r]\) 的无序集合都相同,那么 \([l,r]\) 有序的排在第一个。
考虑枚举一个 \(i\),只计算其后面的 \(j\) 的贡献。注意到 \(s_i\) 和后面字符串的 LCP 其实只有 \(\mathcal O(|s_i|)\) 个且每一个都形成一个区间,可以用单调栈维护这些区间。考虑每一个区间内的字符串,设这个区间和 \(s_i\) 的 LCP 是 \(p\)。根据上面的分析,如果某个 \((i,j)\) 排序 \([p+1,q]\) 是合法的,那一定是 \(i\) 有序而不是 \(j\) 有序,因此极长的有序区间就是 \(s_i\) 的 \([p+1,q]\)。我们需要统计这一段区间内后缀和 \(s_i\) 相同的有几个(由于字符集全都相同,后缀相同必定意味着中间的有序段的无序集合相同),trie 树维护即可。
时间复杂度是优秀的 \(\mathcal O(n|s_i| \log n)\)。
- CF1468B Bakery \(\color{ff0000}2900\)
注意到我们永远卖的是最新做好的面包,因此任意时刻我们都只关心当前时刻最早做好的面包,而只有在清空了当前所有面包的时候才会使得这个时刻发生改变。
我们称一个导致背包清空的位置是 关键位置,答案就是相邻关键位置距离的最大值,因此问题转化为动态维护这些关键位置。
- 观察 A:\(k\) 时刻的关键位置集合是 \(k+1\) 时刻的子集。
- 证明比较显然:考虑 \(k\) 时刻两个相邻的关键位置 \(x,y\),假设它们在 \(x\) 在 \(k+1\) 时刻存在。如果 \(z \in [x+1,y-1]\) 在 \(k+1\) 时刻是关键位置,那么只会导致后面清空的更早,所以 \(y\) 以前一定还存在关键位置;可以推出 \(y\) 一定是关键位置。
- 观察 B:我们只关心距离最远的两个相邻关键位置。
- 因此每次 \(k\) 变化时,我们暂时不用考虑其它线段,只需要考虑最大的那个中间有没有出现新的关键点。
类似超级钢琴的,用一个堆维护所有线段,每次取出长度最大的断成两段。问题转化为,给定 \(k\),怎么快速判断 \([l,r]\) 内是否存在关键位置?
不难发现 \(1 \sim k\) 的每个时刻区间内所有元素都被减 \(1\)。其实我们就是在判断,是否存在 \(i \in [l,r]\) 满足 \(\sum\limits_{j=l}^i a_j - k \le 0\),即区间最小前缀和。把它直接写成前缀和的形式,即 \(sm_j - kj\) 的最小值,发现这是一个一次函数,线段树套李超树维护即可。
时间复杂度 \(\mathcal O(n \log^2 n)\),可以通过。
- CF1455G Forbidden Value \(\color{ff0000}2900\)
首先不难注意到 if
的嵌套形成树结构,且输入是一个 dfs 序。
注意到,你进入了一个 if
时的值时固定的,因此不难想到设计一个 DP:\(dp_{u,i}\) 表示从 \(u\) 子树内出来时的值是 \(i\) 的最小代价。遇到 set
操作给 \(a_i\) 位置赋值成全局 \(\min\) 并给其它位置加 \(v_i\)。离开一个 if
时,需要把这个子树的 dp 数组和其父亲进行合并。暴力合并的复杂度会爆掉,线段树合并即可。复杂度 \(\mathcal O(n \log n)\)。
- CF2039H1 Cool Swap Walk (Easy Version) \(3\color{ff0000}500\)
3500 is not that hard.
首先手玩一些比较规律的操作,不难发现以下两种操作,
- \(\texttt{RDRDRD}\) 可以将数组从 \([1,2,\ldots,n]\) 变成 \([2,3,\ldots,n,1]\)。
- \(\texttt{RRRDDD}\) 可以将数组从 \([1,2,\ldots,n]\) 变成 \([n,n-1,1,2,\ldots,n-2]\)。
注意到每次操作一轮序列的开头和末尾一定会被改变,且循环移位会把数字移到最后,考虑在最后维护有序序列,第 \(i\) 轮将数字 \(i\) 移到数组最后。
假设现在我们在第 \(i\) 轮,且 \(i\) 的位置在 \(pos\),那么数组应当形如 \([\ldots,i,\ldots,1,2,\ldots,i-1]\)。
- 我们希望能让手里拿的数字变成 \(i\),并通过循环移位直接移到最后。大部分情况下,可以直接对 \([1,pos+2]\) 进行操作二,操作完后就有了 \(a_{pos+2} = i\) 并且此时在 \((pos+2,pos+2)\),然后对 \([pos+2,n]\) 进行操作一即可。可以这样操作的前提是进行操作二的时候不会影响已经拼好的部分,也即 \(pos \le n - i - 1\)。
- 剩余情况就比较麻烦,我们无法一次操作内将数字 \(i\) 拿到手里并送到最后。考虑先对 \([1,pos]\) 进行操作二,这样 \(i\) 会跑到序列开头,并向序列最后插入一个随机整数。第二步将 \(i\) 送到序列最后,然后再操作二翻回来,然后再操作一送回去。
第一种情况只需要一次操作,但是第二种需要四次。发现第二种情况出现次数其实比较少,考虑再开始操作以前先瞎几把花费几次操作动一动数组,就可以通过本题 😃
- CF1418F Equal Product \(3\color{ff0000}000\)
不要看到 3000 就以为是难题。
考虑 \(x_1y_1 = x_2y_2\) 这个限制,枚举 \(x_1\) 时首先可以根据乘积的范围求出 \(y_1 \in [L,R]\)。继续考虑 \(x_2,y_2\) 的限制,发现如果 \(x_2 = \dfrac{q}{p}x_1\),那么 \(y_2 = \dfrac{p}{q}y_1\)。显然 \(p\) 是 \(x_1\) 的约数,那么直接枚举 \(p\) 的总复杂度是 \(\mathcal O(n \log n)\)。
枚举 \(p\) 后很容易算出一个 \(q\) 的界 \([l,r]\),我们只需要选出 \(y_1 \in [L,R]\),\(y_2\) 的值就可以得出。为了保证 \(y_2\) 是整数,需要有 \(y_1 \bmod q = 0\)。于是问题转化成,能否从 \([l,r]\) 中选一个 \(x\),从 \([L,R]\) 中选一个 \(y\) 满足 \(y \bmod x = 0\)。请注意这个东西不是单调的。
注意到 \(l,r,L,R\) 都很小,考虑扫描线扫描 \(r\),每次扫一个 \(r\) 时更新 \(r\) 的所有倍数为 \(r\),查询时查询 \([L,R]\) 的最大值是否大于等于 \(l\) 即可。时间复杂度 \(\mathcal O(n \log^2 n)\)。
- CF1425I Impressive Harvesting of The Orchard \(\color{ff0000}2800\)
首先考虑一个 \(\mathcal O(nq)\) 的暴力,然后他 AC 了。以下内容为口胡。
这个修改形式很难处理,考虑根号分治等根号数据结构。注意到树的高度很小,度数也很小,那么对于深度大于等于 \(5\) 的点可以直接暴力做,接下来只需要考虑怎么处理深度比较小的点。
考虑阈值分治,设置阈值 \(B\)。对于 \(a_i > B\) 的点,其只会被更新 \(\mathcal O(\dfrac{n}{B})\) 次,直接暴力的复杂度就是可以接受的,我们只需要考虑 \(a_i \le B\) 的点。
注意到现在剩下的点数和值域都很小了,可以开一个 \(B \times B\) 的数组表示每个点的子树里 \(a_i = j\) 的有多少个。考虑一次清空操作,首先将清空下放到深度为 \(4\) 的节点上,然后清空后向上更新标记即可。时间复杂度大概是 \(\mathcal O(n^{5/3} \log n)\) 的。
看了下题解,发现题解在 \(a_i \le B\) 的时候复杂度是很优秀的。考虑直接枚举 \(a_i\) 的值,然后维护每个点长出果子的时间 \(t_i\),那么一次操作相当于把 \(t_i \le now\) 的 \(t_i\) 变成 \(now + a_i\),使用吉司机线段树维护。复杂度 \(\mathcal O(n^{3/2} \log n)\)。
- CF1458E Nim Shortcuts \(3\color{ff0000}100\)
不要看到 3100 就以为是难题。
不难发现没有 shortcuts 时必败当且仅当 \(x=y\)。
存在 shortcuts 时,除去 shortcuts 之外的地方都可以通过普通博弈论来分析胜负:如果 \(\{(a,y) | a < y\}\) 或 \(\{(x,b) | b < y\}\) 中存在必败态那么 \((x,y)\) 就是必胜态,否则就是必败态。因此不难发现每行除去 shortcuts 外最多存在一个必败位置。
考虑从下到上扫描线维护必败态的位置,从 \(x_1\) 走到 \(x_2\) 相当于填上前 \(x_2 - x_1\) 个空位置。线段树二分后再推平就行了。如果写 \(2\log\) 会被低素质出题人卡常 /fn
- CF1129D Isolation \(\color{ff0000}2900\)
难得有道 2 分钟就会了的 2900,结果还是好几个小时才 AC,感觉最近状态很不好啊。
考虑设 \(dp_i\) 表示以 \(i\) 结尾的方案数,显然有转移 \(dp_i = \sum\limits_{f(j,i) \le k} dp_{j-1}\),问题在于维护合法 \(j\) 的 \(dp\) 数组和。
考虑扫描线扫描 \(i\) 时来维护 \(F_j\) 表示 \(f(j,i) = F_j\),不难发现加入元素 \(a_i\) 后,这个数字的贡献就是 \((pre_i,i]\) 这段区间,给这段区间区间 \(+1\),同时给上一个区间 \(-1\)。
于是问题转化为了区间加法,区间求 \(\le k\) 的数字之和。这是经典的不可 \(\text{polylog}\) 问题,分块解决。注意时间限制比较紧,复杂度不要带 \(\log\):对每个块直接开一个值域桶,由于区间加法只有 \(+/-1\) 且 \(k\) 全局给定,整块可以直接在加的时候维护 \(f\) 的和,避免查询时的二分。
- CF1900F Local Deletions \(\color{ff0000}2800\)
不知道这种 sb 题有什么意义。
注意到相邻两个位置不可能都是 local minimum,因此删除一次序列长度必然至少减半,轮数只有 \(\mathcal O(\log n)\) 轮。
考虑带有区间询问怎么做,注意到只有端点位置的状态可能和全局的不相同,而端点部分的数字个数不会超过 \(\mathcal O(\log n)\) 个。边上的部分直接模拟就好了。
除了代码比较难写以外就是个从头到尾的水题。
- CF1088F Ehab and a weird weight formula \(\color{ff0000}2800\)
注意到如果以最小的 \(a_i\) 为根,根到叶子的路径点权单调不降。证明从叶子反推即可。
同时考虑点权边权很难受,不妨把点权拆到边上,一条边的代价是 \(\lceil \log_2 dis(u,v) \rceil \min(a_u,a_v) + a_u + a_v\)。由于求的是 MST,不难发现向兄弟连边不如直接向祖先连边,所以每个点只需要考虑向祖先的出边。固定 \(k\) 时显然只需要考虑其 \(2^k\) 级祖先,只保留这 \(\mathcal O(n \log n)\) 条边跑 MST 的复杂度就是 \(\mathcal O(n \log^2 n)\),但是过不了。注意到每个点一定会从它往上连的边里选一条,直接对每个点取 \(\min\) 加起来即可。
直接做不容易,考虑二分答案 \(mid\),一个矩形障碍相当于限制,如果左上角要在 \((x_1-mid+1,y_1-mid+1,x_2,y_2)\) 这个矩形内,则需要付出 \(c\) 的代价。相当于矩形加,全局 \(\min\),直接线段树扫描线即可,但是复杂度是大常数 \(2 \log\),过不了最后一个 subtask。
\(b = 0\) 的特殊情况下,我们需要优化掉一个 \(\log\)。二分答案后相当于判定这些矩形的覆盖面积是否是全集,但这是很难线性完成的。想要优化只能直接干掉二分答案。
考虑枚举矩形右边界 \(r\),左边界 \(l\) 显然有单调性,可以双指针。\([l,r]\) 合法的充要条件是存在一段长度为 \(r-l+1\) 的 \(y\) 轴区间使得没有任何障碍,相当于要做区间加减,全局查最长 \(0\) 段。这里是套路积累:维护 \(0\) 段不容易,但是维护最小值连续段很简单,因此改为维护最小值连续段即可。复杂度一个 \(\log\)。
先考虑 \(k=1\) 怎么做,其实这就是经典题 ABC346G:枚举那个出现恰好一次的位置,它要恰好出现一次相当于需要 \(l \in (pre_i,i],r \in [i,nxt_i)\),矩形面积并即可。
类似的,我们依次枚举 \(k=1,2,3,4\) 的位置,可以得到四种颜色的矩形,问题是四种颜色都有的面积是多少。这个问题不好解决,我们会算的是四种颜色至少有一个的面积。因此考虑容斥将颜色的交改写成并,扫描线即可。复杂度 \(\mathcal O(2^kn \log n)\)。
首先考虑怎么判断是否有解。将抽象的对称操作用代数语言描述:其实是令 \(x \gets 2c - x\)。在一大堆操作之后 \(x\) 会变为 \(2(c_1-c_2+c_3-c_4+\ldots) + (-1)^k x\)。此时如果有 \(x' = y'\),则将 \(x,y\) 移到另一边后两两配对 \(c\),不难发现一次操作的贡献是 \(2(c_x - c_y)\)。
为了方便把 \(2\) 除掉。相当于一次操作可以任选一个 \(c_x - c_y\) 加上或减掉,问若干次操作后能否把手里的数变成 \(x-y\)。根据裴属定理,能得到 \(d\) 的充要条件是 \(\gcd(S) | d\),因此只需要判断 \(x-y\) 是不是 \(\gcd\) 的倍数。将 \(c\) 排序后求邻项 \(\gcd\) 即可。至此终于拿到 \(11\) 分。
考虑一般情况的解决方案,首先二分答案 \(mid\)。只要 \(f_i - f_j \le mid\) 那么 \(c_i - c_j\) 就可以贡献进 \(\gcd\),判断是否有 \(\gcd | x-y\) 即可。复杂度 \(\mathcal O(qn^2 \log n)\)。
很难不想到按 \(f\) 排序,然后立刻注意到一个 \(i\) 满足 \(|f_i - f_j| \le mid\) 是一个区间。这个区间里两两的 \(\gcd\) 都可以计入贡献,把 \(n\) 个区间的贡献在 \(\gcd\) 在一起即可。复杂度 \(\mathcal O(nq \log n)\)。
根据经典结论,我们只需要求差分数组的 \(\gcd\),即可得到两两差的 \(\gcd\)。拿区间去覆盖线段,只要被覆盖至少一次的线段就可以 \(\gcd\) 进最终的贡献。发现,只要 \(f_i - f_{i+1} \le mid\) 就一定会被覆盖,反之一定不会。由此发现答案也只有 \(\mathcal O(n)\) 个,主席树维护每一个版本的可以选的线段的 \(\gcd\) 后二分查询。复杂度 \(\mathcal O(n \log ^2 n + q \log^3 n)\)。
考虑询问点 \(x\),如果结果是 \(1\) 则淘汰 \(n - siz_x\) 个点,否则淘汰 \(siz_x\) 个点,我们希望这两者尽可能均衡。发现这其实就是边分治的过程,原树已经是三度化之后的结果。每次找重心边即可。
询问次数是严格 \(\log\),应当不难想到二分状物。但问题是我们的询问不足以判断一个子集里是否包含根:如果返回 No 则一定不包含根,但是返回 Yes 不一定包含根,没有办法直接二分。
我的初步想法是,随机打乱编号,然后进行二分或者二进制分组,但是都会在 \(n\) 比较小或者 \(n\) 是 \(2\) 的次幂附近的数的时候寄掉。然后你发现这两个做法甚至都没有利用树形!
这里需要人类智慧。注意到叶子是比较特殊的,两两不容易成祖先关系。考虑带上所有叶子进行询问:如果根是叶子,则直接在叶子里二分;否则每次询问带上所有叶子。问题是需要先判定根是否是叶子,询问次数是 \(\log_2 n + 1 = 10\),可以得到 \(83\) 分。
优化到满分不难:考虑重新标号,把 \(m\) 个叶子标号为 \(1 \sim m\),剩余的标号 \(m + 1 \sim n\),在这个新序列上直接二分就可以省去判断根是否是叶子。注意一些 \(|S| = 1\) 的特判。
傻逼出题人把 hack 数据藏 test 2,你妈真死了。
注意到最终好序列的形态一定是奇数位置全相同,偶数位置全相同。那么立刻想到找到奇数位置出现次数的最大值 \(x\) 和偶数位置出现次数最大值 \(y\),答案是 \(n-x-y\)。但是 test 2 就挂了:
1
9
1 2 1 2 3 1 2 1 2
注意到这组数据如果我们想把序列改成 1 2 1 2 1 2 1 2 1
,中途会导致序列不是好的。因此我们还需要考虑,修改中途造成的额外开销。具体的,对于一个奇偶性相反的连续段 \([1,2,1,2,1]\),如果我们想改成 \([2,1,2,1,2]\),不难想到把中间两个 \(2\) 先改成 \(3\),然后再操作。给更一般的,一个长度为 \(len\) 的反色连续段需要 \(\lfloor \dfrac{len}{2} \rfloor\) 次额外操作。
问题转化为选择 \(x,y\),贡献是 \(c_x + d_y - f_{x,y}\),最大化贡献。这是经典问题,将 \(d\) 数组降序排序,然后暴力枚举直到不存在 \(f_{x,y}\),由于 \(f_{x,y}\) 只有 \(\mathcal O(n)\) 个,复杂度均摊正确。
考虑没有 \(l\) 的限制怎么办:我们显然会先去走 \(r\) 小的边。每次找到 \(r\) 最小的点,然后在反图上遍历后面的点。
考虑有了 \(l\) 的限制怎么做:我们仍然想要先去走 \(r\) 小的点。不妨设 \(t_i\) 表示 \(i\) 能到的 \(r\) 最小的值,我们希望按照 \(t_i\) 从小到大遍历。如果 \(l\) 的限制还不满足就先扔进堆里待用即可。
官方题解提供了另一种简洁做法:考虑 \(m = 0\) 怎么做,一种贪心是按照 \(r\) 升序排序,然后删掉最小的可用的大于等于 \(l\) 的点,正确性显然。
考虑对每条边 \(u,v\) 更新限制 \(l_v \gets \max(l_u + 1,l_v),r_u \gets \min(r_v - 1,r_u)\),正反做两遍拓扑排序即可。这样之后直接跑上述贪心。根据贪心过程,贪心出来的结果一定就满足 \(p_u < p_v\) 了。
考虑 MST 是 \(1 \sim n-1\) 的边实际上意味着什么:对于每一条非树边 \((u,v)\),其边权应当大于路径上所有树边。对偏序关系建图后就转化为上面的问题,但是显然不能暴力建图。
考虑模拟上面的做法二。注意到深度只有 2,只需要做一次取 \(\max,\min\),根本不需要拓扑排序。我们需要做路径取 \(\max\) 和路径推 \(\min\),前者直接倍增,后者差分后可并堆维护,复杂度 \(\mathcal O(m \log m)\)。
开题先写贪心,发现第一个样例挂了,但是有 38 分,挂的点都是 \(m=2\)。简单观察发现 \(m\) 很大的数据答案都是 \(0\)。
这个感性理解确实很对,因为当决策很多的时候,先手总能清空正数,而后手总是能清空负数。
于是 \(m\) 比较小的时候跑搜索,\(m\) 比较大直接输出 \(0\),实测取阈值 \(30\) 就可以通过。
(观察发现数据里最大的非 \(0\) 是 \(m=27\)!)
考虑一下怎么证明结论。一个最简单的 case 是 \(a_i \ge 1\),不妨只考虑先手的决策。如果每次先手挑元素多的一边去删除,那也只需要 \(\log n\) 次就可以变成 \(0\)。因此立刻得到 \(m \le 2 \log_2 n\)。
存在负数时决策会更加复杂,此时不能再简单的假设先手选多的一边了,因为可能会导致和变大。这里官方题解给了一个巧妙的证明:如果先后手都可以通过自己的回合删去所有元素,那么答案一定是 \(0\)(先手可以使答案不大于 \(0\),后手可以使答案不小于 \(0\))。因此这直接证明了 \(m \le 2 \log_2 n\)。
差点没做出来红题。
考虑字符串哈希,问题是怎么快速求一个变换后的串的哈希值。
考虑从 \(2^k\) 到 \(2^{k+1}\) 的过程,相当于给前半部分末尾加了一个 \(0\),后半部分末尾加了一个 \(1\)。记 \(2^k\) 时的蝶变串为 \(s\),不难发现新字符串是 \(t = s_0s_{2^k}s_1s_{2^k+1}\ldots\)。
考虑维护哈希值 \(f(s) = \sum b^is_i\),偶数位置都是左半部分,奇数位置都是右半部分。对比偶数部分的系数,在 \(f(t)\) 中是 \(\sum b^{2i}t_{2i}\),而在 \(f(s)\) 中是 \(\sum b^is_i\),相当于偶数位置贡献是 \(\sum b^{2i}s_i\),奇数位置是 \(\sum b^{2i+1}s_i\)。
那么不难想到维护 \(f(i,j,k)\) 表示 \([i,i+2^j-1]\) 这个串的 \(\sum b^{2^ki}s_i\) 的值,直接倍增预处理即可。显然两个 \(\log\) 空间会爆炸,顺序预处理时可以省略 \(j\) 一维,回答询问只需要额外记录 \(ok_{i,j}\) 表示 \([f(i,j,0) = s[i,i+2^j-1]]\) 即可。
最终时间复杂度 \(\mathcal O(n \log^2 n)\),空间复杂度 \(\mathcal O(n \log n)\)。
- \(^*\) loj3629 「2021 集训队互测」序列
感觉再给我点时间能做出来的。
一种比较正常的思考方式是,将中位数等于 \(x\) 这个条件转化为,中位数大于等于 \(x\) 且中位数小于等于 \(x\)。这里就比较套路了,中位数大于等于 \(x\) 可以描述为任意两个数都至少有一个大于等于 \(x\)。
考虑如果值域比较小怎么做。设置 \(nv\) 个变量 \(v_{i,j}\),表示 \([a_i \le j]\) 是否成立。不难发现几条限制:
- 如果 \(v_{i,j} = 1\),那么 \(v_{i,j+1} = 1\)。
- 如果 \(v_{i,j} = 0\),那么 \(v_{i,j-1} = 0\)。
- 还有上面说的三元组带来的限制。
不难发现这是 2-sat 问题,直接跑 2-sat 即可。
注意到对于一个 \(i\),涉及到它的 \(v\) 不多。所有 \(v\) 的数量之和是 \(\mathcal O(m)\) 的,因此复杂度均摊正确。总复杂度 \(\mathcal O(n + m)\),常数巨大。
- \(^*\) P4610 [COI2012] KAMPANJA
神秘。
首先处理出来 \(x \to y\) 的最短路 \(d_{x,y}\)。
注意到答案不是 \(d_{1,2} + d_{2,1}\) 的原因是相同的点只算一次。于是想到设计一个 dp,设 \(f_{i}\) 表示 \(1 \to i \to 1\) 的环的最小代价,答案是 \(f_2\)。转移是 \(f_i = \min\{f_j + d_{i,j} + d_{j,i} - 1\}\),类似最短路进行转移。
但是这样有一些问题,会被样例 hack 掉,原因是可能有 8 字形状的环,中间自己交了一段相同的路径。但是不难发现交最多就是一段路径,因此 dp 状态改为 \(f_{i,j}\) 为 \(1 \to i \to j\) 的环的最小代价即可。复杂度应该不会太高 /tiao
- \(^*\) P3561 [POI2017] Turysta
强连通的竞赛图一定有哈密顿回路。考虑首先找到一条哈密顿路径 \(p\)。
-
首先找到第一个连向 \(1\) 的点,这样我们就得到了一个初始环。
-
然后找到路径 \(v \to u\) 上第一个向环连边的点 \(u\)。
- 如果 \(v = u\),此时由于是哈密顿路径,必然存在一条从回路向 \(u\) 连的边。也就是存在相邻两个点 \(x,y\) 满足 \(x \to u \to y\),将 \(u\) 在这里插入。
- 否则找到 \(u \to x\) 中 \(x\) 的前驱 \(y\),则 \((y,v)\) 之间的边一定是 \(y \to v\)。此时存在路径 \(y \to v \to u \to x\),将这段路径整段插入即可。
神秘题。
神秘的修改方式让 ds 很难维护,但是 ds 题也是可以找性质的!
任意时刻点 \(x,-x\) 的答案一定互为相反数。
这个是显然的:因为每一次 \(x,-x\) 的操作都是对称的,因此它们之后会一直成相反数。
值域不大,考虑维护值域内每个点的答案,设当前在维护同符号区间 \([l,r]\)。考虑如果原点 \(p\) 平移进入了区间 \([l,r]\),那么短的那一侧可以直接由长的那一侧推出来,我们之后不再需要计算这个区间的答案。直接暴力模拟这一过程即可,复杂度 \(\mathcal O(n+m+v)\)。
- CF1765G Guess the String \(\color{ff0000}2800\)
考虑如果把 \(p,q\) 都告诉你怎么做,不难发现其实只有 \(p_i\) 就可以确定整个字符串。
- 如果 \(p_i = 0\),那么 \(s_i = 1\)。
- 否则 \(s_i = s_{p_i}\)。
显然这样需要 \(n-1\) 次询问,不能通过。
询问次数大概是 \(0.75n\),首先考虑的是用 \(3\) 次询问确定 \(4\) 个位置,但这是很困难的。
我一开始想了一个随机化做法,随机询问 \(700\) 个位置,利用这些位置覆盖到其他地方。没有被覆盖的地方应该不会太多,单独询问它们。但是被 \(01111111\ldots\) 卡爆了。
注意到上述字符串 \(p_i = 0,q_i = 1\),很难有什么有效的询问策略。考虑从 border 或反 border 的不存在入手,如果前缀不存在长度为 \(2\) 的 border,那么 \(s_{i-1} \ne s_1\) 和 \(s_i \ne s_2\) 至少有一个成立。对所有偶数位置顺次随机询问,有 \(1/2\) 的概率可以顺带着问出 \(i-1\),故期望询问次数 \(3/2n\)。
首先不难想到去考虑每个 \(a_i\) 对答案的贡献。打表发现位置 \(i\) 对 \(2^n\) 的前缀和 \(j+1\) 次造成贡献当且仅当 \(i \& j = 0\)。有了这个直接瞎几把高维前缀和维护即可。
考虑证明。前缀和 \(k\) 次经典的组合意义是,从 \((1,1)\) 走到 \((k,n)\) 的向右下格路数量,即 \(\binom{n-1+k-1}{k-1}\),模 \(2\) 意义下运用 Lucas 定理,要求 \(k-1\) 是 \(n-1+k-1\) 的子集。
\(b\) 是 \(a+b\) 的子集要求的其实是 \(b\) 和 \(a\) 不交。如果 \(b\) 和 \(a\) 有交,找到它们的公共 lowbit,这一位上 \(a+b\) 一定是 \(0\),矛盾。因此证毕。
手玩一下就会了的题。
注意到,如果 \(a_{n-1} + 1 \ne a_n\),考虑状态 \(\{a_1,a_2,\ldots,a_n - 1\}\)。
- 如果这个状态是必败态,那么先手直接获胜。
- 否则,考虑这个状态是往哪里转移以获胜的。由于原状态必定也能到达这个状态,故先手仍然必胜。
因此如果 \(a_{n-1} + 1 \ne a_n\) 那么先手直接获胜。否则,双方一定会保持 \(a_n = a_{n-1} + 1\),。且最大值每次减少 \(1\),故直接根据 \(a_n - n\) 的奇偶判断即可。
实际上上面的观察本质上是一个博弈论中的定理:
对于状态 \(S\) 如果存在一个状态 \(T\),满足 \(S \to T\) 且对于所有 \(T \to P\) 都有 \(S \to P\),则 \(S\) 是必胜态。
这也太难了,,,
一个很好的思路是,用类似 \(142857\) 的数字是去构造,因为其 \(1 \sim 6\) 倍都是其自身的循环移位。
观察 \(142857\) 这种数的性质,发现所有有原根 \(10\) 的质数 \(p\),\(1/p\) 的循环节都满足上述性质。本题选取 \(p=1019\) 即可。
考虑为什么这样的 \(1/p\) 会有这样子的性质。考察你做竖式除法的过程,实际上是每次给 \(x\) 乘 \(10\),商写下 \(x / p\),然后 \(x \gets x \bmod p\)。由于 \(x\) 最多有 \(p-1\) 个,所以循环节长度最多是 \(p-1\)。
不难发现一个数如果需要是纯循环小数,需要满足最小周期是 \(p-1\),这样才能满足所有 \(1\sim p-1\) 的倍数都是其自身的循环移位。那由于 \(a^{\varphi (p)} \equiv 1 \pmod p\),首先我们要求 \(p\) 是质数;其次要求 \(p\) 有原根 \(10\)。
- \(^*\) [ARC137E] Bakery
神秘。还是太不会流了。
朴素的想法应当是对人和天分别建点,但是很难限制面包师的代价,很难做到要么都选要么都不选。
这种一个人管辖一段区间的问题,一个可能比较套路的做法是,将问题抽象在一个 \(n+1\) 个点的数轴上,原本的一天代表一条边,然后区间就变成了数轴上的一段线段。
考虑先钦定所有 \(a_i\) 都选满。\((i-1,i)\) 每次流过 \(1\) 的流量表示 \(i\) 这天少做了一个面包,那不难根据这个意义连边 \((i,i+1,a_i,d),(i,i+1,m-a_i,0)\)。对于一个面包师,如果选择了他相当于跳过 \((l,r)\),因此连边 \((l-1,r,1,c_i)\)。跑限制流量为 \(m\) 的最小费用流即可。
为什么不能不钦定选满 \(a_i\)?如果决策是,选择一个面包师并加上贡献,那么跳过的是前后缀,前后缀的组合是不好处理的!
和上面那个题差不多,仍然是把选择区间 \(+1\) 刻画成跳过一段区间。
连边 \((i-1,i,n\inf - a_i,0)\) 和 \((l-1,r,\inf,c_i)\) 即可。
- \(^*\) P4859 已经没有什么好害怕的了
二项式反演。设 \(f_i,g_i\) 是恰好选 \(i\) 个和至少选 \(i\) 个的方案数,根据定义应当有 \(g_i = \sum \dbinom{i}{j}f_j\)。有时 \(g\) 比较好求但是 \(f\) 不好求,此时二项式反演,有 \(f_i = \sum\limits_{j\ge i} (-1)^j \dbinom{j}{i} g_j\)。
首先给 \(a,b\) 排序。注意到恰好配 \(k\) 对是困难的,因为你很难确定一个不配对元素到底配对上了没。这时候就考虑去求钦定配 \(k\) 对的方案数,这样我们就不关心一个不配对元素的去向了。
设 \(dp_{i,j}\) 表示 \(a\) 中选前 \(i\) 个配了 \(j\) 对的方案数。注意到第 \(i\) 个元素匹配范围是第 \(i+1\) 个的子集,可以直接有 \(dp_{i,j} \to dp_{i+1,j},dp_{i,j} \cdot (r - j - 1) \to dp_{i+1,j+1}\)。复杂度 \(\mathcal O(n^2)\)。
- \(^*\) [ARC101E] Ribbons on Tree
感觉是唐题啊,是我先听 sol 再看题导致的吗。
首先考虑容斥,断掉一些边后,每个连通块内部配对可以任意,贡献 \((sz - 1)(sz - 3) \ldots 1\),大小要求是偶数。
于是自然考虑 DP。注意到连通块贡献只和大小有关,直接树背包合并即可。
很厉害的题,但是直接猜就好了,,
第一直觉肯定是,直接输出所有点权的 \(\gcd\),但是发现被样例 hack 了。进一步发现如果两个右部的点入点集合相同,那它们两个永远会被在一起计算,故需要将它们合并。然后再求 \(\gcd\) 就 AC 了!
一个很厉害的证明:
记 \(f(S)\) 是左部点集合 \(S\) 连接的右部点的点权和,\(g(u)\) 是右部点 \(u\) 对应的左部点集合。现在假设 \(g(u)\) 互不相同。
首先答案一定是 \(\gcd(a_i)\) 的倍数,先将所有 \(a_i\) 除以这个 \(\gcd\),接下来只需要证明答案等于 \(1\)。
考虑对于任意一个 \(k > 1\),我们都要找出一个左部点集合使得 \(f(S)\) 不能被 \(k\) 整除。如果整个左部点集合的 \(f\) 不能被 \(k\) 整除,那么就已经找到了 \(S\)。否则,找一个右边度数最小的 \(v\) 满足 \(a_v\) 不能被 \(k\) 整除,令 \(S\) 等于 \(g(v)\) 的补。
考虑怎样的 \(a_w\) 不会在 \(f(S)\) 中出现,需要满足 \(g(w)\) 是 \(g(v)\) 的子集。由于 \(g\) 互不相同且 \(|g(v)|\) 已经最小,故这样的 \(w\) 不存在,因此 \(f(S) = sum - a_v\),这个值显然不能被 \(k\) 整除,证毕。
经过大量手玩和观察,发现一对排列 \((a,b)\) 合法的充要条件是 \(\forall i \in [1,n],b_i \ge a_i - k\)。数数部分是平凡的。
证明不是特别困难:首先为了方便将 \(b\) 重排成 \(1,2,\ldots,n\)。
- 观察 \(1\):第 \(i\) 次操作一定有 \(x = i\)。
- 如果此时 \(a_i \ne i\),那显然必须要换,不然没机会换了。
- 否则,此时操作 \(x\) 必定不等于 \(i\)。但是由于这次操作的 \(r\) 太小,进行别的调整是没有意义的,因此不会进行操作。
考察第 \(i\) 次操作。这里的 \(a_i\) 指的是原本序列,\(a'_i\) 指的是当前序列。
- 如果 \(a_i \ge i\),那显然 \(a_i\) 不会在前 \(i-1\) 次操作移动。这次操作的代价是 \(a_i - i\)。
- 否则,\(a_i\) 一定已经被移动到了某个位置 \(j < i\)。注意到此次交换的代价是 \(a_i' - i\),而把 \(a_i'\) 换过来的代价是 \(a_i' - j\),在 \(j\) 处计入答案即可。
因此整个过程需要的最大代价是 \(\max a_i - b_i\),故合法条件为 \(b_i \ge a_i - k\)。
感觉听人讲这题好多次了啊,
考虑 \(x \to \varphi (x)\) 连一条边,这会形成一棵树,且树的深度是 \(\mathcal O(\log n)\)。那么操作一直接上势能线段树暴力做就好了。对于操作二其实就是找 LCA 的深度,维护 dfs 序上的 \(\min,\max\) 即可。
- 给定一个长度为 \(n\) 的序列,支持 \(q\) 次操作,每次操作是:
- 操作 A:区间 \([l,r]\) 加上 \(k_i\)。
- 操作 B:查询区间 \([l,r]\) 从操作 \(t_i\) 之后的历史最大值。
- \(1 \le n,q \le 2 \cdot 10^5\)。
首先 \(t_i = 1\) 时是经典的线段树维护历史最值,但是这个维护方法不可能支持带上时间信息。
如何将时刻 \(t_i\) 之前的信息减去?不难想到对时间轴分治,每次处理跨过区间 \(mid\) 的查询。
每次从 \(mid\) 出发往两边扩展时,初始状态应该是和是 \([1,mid]\) 操作后的和,但是历史和是 \(-\infty\)。考虑类似 cdq 分治的,先递归左区间,区间处理完后只保留和信息,清空历史和。
如何清空历史和?tag 信息里额外维护一个,当前历史和是否被清空过。合并 tag 会多一些讨论。
套路的转差分,一次操作会单点修改两个位置,因此答案是差分数组中 \(1\) 的个数 \(cnt\) 除 \(2\) 上取整。
注意到总和是好统计的,考虑拆开贡献,分讨每一个 \((i,i+1)\) 不同的条件。不难发现,如果数对里有问号那么有 \(1/2\) 的序列里会造成贡献。
给总和加上,\(cnt\) 是奇数的序列数量再除以 \(2\) 就可以得到答案,问题转化为求 \(s_i \ne s_{i+1}\) 的下标 \(i\) 数量是奇数的方案数。
我的做法是首先对于单个 \(s\) 枚举左右端点并 dp 出答案,然后矩阵快速幂解决更大的 \(k\)。但这也太傻逼了,考虑 \(s_{i} \ne s_{i+1}\) 的段数是奇数等价于 \(s_1 \ne s_{n}\),直接统计即可。
- \(^*\) [ARC144D] AND OR Equation
打表发现序列合法的充要条件是,每个 \(2^k\) 的段的差分数组相等。不会证明。
考虑对这个进行计数。相当于一开始从一个点出发,每次可以选择不变,或者向外扩展区间。对这个东西进行方案数计数。
从前往后做不好做。不妨直接考虑最终扩展后的形态,枚举最终长度 \(len\),答案为
最后那个式子的含义是,首先枚举扩张次数 \(i\),然后选择 \(i\) 个位置,然后每个位置可以选择左右。最后,\(i\) 个位置一共扩展 \(len\),插板得出方案数。
接下来是推式子环节,需要若干次上指标求和。不是很难推。
首先考虑没有 \(-1\) 怎么做。如何判断所有 \(1 \to n\) 的路径上边权的和是否都是 \(g\) 的倍数?
可以考虑直接做拓扑排序。设 \(p_u\) 表示所有 \(1 \to u\) 的路径模 \(g\) 的值,显然 \(p_u\) 需要是唯一的,直接 check 即可。
在 \(g\) 不确定的时候就不太好办了。考虑建一张新图 \(G'\),拆点。每个原图中的点拆成入点和出点,原图的一条有向边在新图里连双向边,同时连边 \((i,i + n,a_i),(i+n,i,-a_i)\)。
我们断言新图里所有环边权和的 \(\gcd\) 就是原问题的答案。注意拆点是很关键的一步,拆完点后一个环最多是由两条有向路径一正一反拼起来的。
然后可能就是 trick 的积累。找所有环的 \(\gcd\) 只需要找包含 \(1\) 条非树边的环的 \(\gcd\),求出生成树做即可。
对于 \(-1\) 边,处理不是很困难。直接不连 \((i,i+n)\),求出 \(g\) 后这些点点权全都赋值成 \(g\) 即可。
ad-hoc,但是拼尽全力成功战胜!!!
令 \(p = 998244353\)。注意到 \(\{x^2 \bmod p\}\) 的值只有 \(p/2\) 个,\(\{x^4 \bmod p\}\) 的值只有 \(p/4\) 个,。
因此考虑每个数字放 \(2^B\) 个,一个区间的乘积可以近似看作 \([1,p/2^B]\) 内的随机数。一个序列一共有 \(n(n+1)/2\) 个区间,考虑取 \(B=16384,n = 16384 \times 30\),可以通过。
- \(^*\) CF1688C Manipulating History
不妨把最后的串看作一次清空操作,那么最后串空。
考虑一些比较特殊的情形,比如 \(|t_i| = 1\)。除了初始字符之外的所有字符都会经过插入删除两次成对的操作,都应该出现偶数次。初始字符少一次插入,出现奇数次。
\(|t_i| > 1\) 时是相同的。
- \(^*\) CF618F Double Knapsack
困难构造题。
首先要进行一步关键的转化:选择子集可以转化为,重排后选择子区间。
假设 \(sum_a \le sum_b\)。对于每一个 \(i\),找到最小的 \(j\) 满足 \(sa_i \le sb_j\),显然 \(sb_j - sa_i \in [0,n)\)。当 \(i\) 取遍 \([0,n]\) 时必然产生重复的 \(sb_j - sa_i\),取一个重复的即可。
很优美的题 /se
令 \(k \gets n - k\),原问题等价于将序列划分成 \(k\) 个子序列,最大化 \(\gcd\) 之和。
感性猜测不会有太多集合包含不等元素。事实上,满足 \(\min(S) \ne \max(S)\) 的集合 \(S\) 最多只有 \(1\) 个。
- 引理:若 \(\min(S) \ne \max(S)\),则 \(2\gcd(S) \le \max(S)\)。
- 证明显然。
- 那么如果存在两个包含不等元素的集合 \(S_1,S_2\),那么此时他们的和 \(s \le (\max(S_1) + \max(S_2)) / 2\)。显然可以把 \(\max\) 单独放一个,剩下的放另外一个,这样的和 \(s' \ge \max(\max(S_1),\max(S_2)) \ge s\)。
注意到选择一个 \(S\) 会使得答案减少 \(\sum s_i - \gcd(S)\),而 \(\gcd\) 其实是一个比较小的值。因此感性猜测 \(S\) 的形态大致是排好序后的一个前缀。事实上,\(S\) 一定是一个前缀拼上一个额外元素组成的。
反证法:如果 \(i>j>k\) 且 \(a_i \in S,a_j \in S,a_k \not \in S\),那么有 \(\gcd(S) \le a_i - a_j\),因此 \(\sum s_i - \gcd(S) \ge 2a_j + \text{left}\),而如果此时仅把 \(a_i\) 换成 \(a_k\),得到的是 \(\sum s_i - \gcd(S) \le a_j + a_k + \text{left}\),显然不劣。
相同的 \(a_i\) 划分在一个集合里对 \(\gcd\) 没有影响,唯一的作用是单开一个集合。不妨枚举 \(|S| = i + 1\),那么单开集合的数量被立刻确定,直接取最大的若干个即可。此时 \(|S|\) 中已经选择了 \(a_1 \sim a_i\),如果前缀 \(i,i+1\) 的 \(\gcd\) 相同显然直接选 \(i+1\) 最优;否则这种情况只会出现 \(\mathcal O(\log V)\) 次,暴力枚举另一个元素即可,复杂度 \(\mathcal O(n \log^2 V)\)。
- \(^*\) CF2061G Kevin and Teams
\(k\) 的值猜错了和室友一起构造若干小时无果,what can i say。
关键结论:\(k = \lfloor \dfrac{n+1}{3} \rfloor\)。
- 证明 \(k \le \lfloor \dfrac{n+1}{3} \rfloor\)。
考虑一张 \(3k+1\) 个点的图,\((i,j)\) 有边当且仅当 \(i,j \le 2k+1\)。这样,有边的部分是一个 \(2k+1\) 个点的团,最大匹配为 \(k\)。没有边的每一个数对 \((i,j)\) 都要占用一个 \(>2k+1\) 的点,因此最大匹配也是 \(k\)。
- 证明 \(k \ge \lfloor \dfrac{n+1}{3} \rfloor\)。
考虑直接构造证明,维护一条同色链,设最后两个点是 \(u,v\),尝试加入点 \(i\),首先询问 \((v,i)\)。
- 如果颜色相同则直接加入。
- 否则,删除 \(u,v\),创建一个三元组 \((u,v,i)\)。
设最后形成了 \(x\) 个三元组,则链的长度应该是 \(n-3x\)。考虑从链上取 \(\lfloor \dfrac{n-3x}{2} \rfloor\) 个匹配,从每个三元组中取 \(1\) 个匹配,则 \(k = \lfloor \dfrac{n-3x}{2} \rfloor + x\)。我们关心 \(k\) 的最小值是多少。
\(k\) 显然是随 \(x\) 递增不增的,因此 \(x = \lfloor \dfrac{n}{3} \rfloor\) 时就是 \(k\) 的最小值。分类讨论 \(n \bmod 3\) 的值:
- 如果 \(n \bmod 3 = 0\),那么 \(x = k = \dfrac{n}{3}\)。
- 如果 \(n \bmod 3 = 2\),那么 \(x = \dfrac{n-2}{3},k = 1+x=\dfrac{n+1}{3}\)。
- \(n \bmod 3 = 1\) 的情况严格弱于 \(n \bmod 3 = 0\) 的情况,可以忽略。
因此我们构造出了一组 \(k = \lfloor \dfrac{n+1}{3} \rfloor\) 的解。
- \(^*\) P1224 [NOI2013] 向量内积
wyr 姐姐 /bx /bx /bx
好像在场上发现了一些观察,但漏掉了一些,导致只会巨大难写的 ds 做法。我怎么能这么糖的。
注意到选择点 \(i\) 的代价已经大于选择 \(1 \sim i-1\) 的所有点,因此可以设计一个贪心:从大到小枚举 \(i\),看删除 \(i\) 后是否存在一个连通块包含 \(1 \sim n\) 的所有颜色,如果有就删掉。复杂度 \(\mathcal O(n^2)\)。
一个比较重要的观察是,删除一个元素 \(x\) 后,设 \(x\) 的另一个出现是 \(r\),再删除别的元素保留的连通块都是那个包含 \(r\) 的。我们可以以 \(r\) 为根建树,这样删除的必定是一个子树。考虑删除带来的限制,我们不能选择子树内同时含有某个颜色两次的点。在 lca 处打标记,子树内不能包含 lca。删除每个点只有一次,复杂度均摊正确。
问题是怎么找 \(r\)。这是简单的,考虑 \(r\) 断开后要么合法的是某个子树,要么是某个子树的补,差分一下即可。总复杂度 \(\mathcal O(n \log n)\)。
- \(^*\) CF2062F Traveling Salescat
第一步转化相当困难。
这个 \(\max\) 的形式比较难受,能不能让它好看一点?
设 \(x_i = \frac{a_i + b_i}{2},y_i = \frac{a_i - b_i}{2}\),那么原本的 \(\max(a_i + b_j,a_j + b_i) = \max(x_i + x_j + y_i - y_j,x_i + x_j + y_j - y_i)\),也就等于 \(x_i + x_j + |y_i - y_j|\)。
分开考虑 \(x,y\) 的贡献。不难发现除了首尾以外所有 \(x\) 的贡献系数都是 \(2\),而首尾的贡献 \(1\)。也就是说,除了首尾外,我们走过的顺序都是按照 \(y\) 有序的。这就可以 DP 了。
设 \(dp_{j,k}\) 是选了 \(j\) 个且状态为 \(k\) 的最小值,这里状态只有 \(3\) 种:起点终点都没有选,起点选了终点没选,起点终点都选好了。分讨转移。
由于最后一个选的点的贡献系数多一个 \(y\),实现上可以单独记一个 \(ans\) 数组,对于每个状态把 dp 值给贡献上去。
- \(^*\) CF2055F Cosmic Divide
新年第一题。神秘暴力小题。
首先切出来的两部分一定都是凸的,因为两个不凸的全等多边形拼一起不可能是凸的。
先特判掉水平和竖直对半切两个特殊 case,剩余情况一定是,前 \(c-1\) 行都划分给一个,下面的行再去分。
不失一般性的,假设切分后两个图形在右上和左下。设第 \(i\) 行的切分点是 \(pos_i\),既然是全等的,那必然满足 \(pos_i = pos_c + r_{i-c+1} - r_1\),即右端点的偏移量相等。同理可以根据左端点推出一个 \(pos_i\) 的表达式。
然后求出 \(pos_i\) 后还需要检验:
- 后 \(c-1\) 行需要有 \(pos_i = r_i\)。
- 每一行的长度相等,且图形连通。
暴力做的复杂度是 \(\mathcal O(n^2)\)。
注意到条件二是相当难检验的,这时候有一个神秘乱搞:如果前面的所有条件全都满足,我就直接暴力检验条件二。然后就 AC 了。
官方题解证明了这样的枚举量有一个很宽松的上界 \(\mathcal O(\sqrt n \log \log n)\),但是看不懂一点。摆烂。
感觉没做出来这个题是被榜严重误导了,时刻记住外国人不会 ds,看到 ds 题难度减 400。
可以先枚举每一个点后暴力跑 E1 的算法,复杂度 \(\mathcal O(n^2 \log n)\)。这其实是最难想的一步,后面的都是简单 ds。
定义一个点是坏的当且仅当删除后立刻无法操作,否则点是好的。我们需要让删除一个子树后,所有点都是坏的。
仍然从大到小加点,考虑加入某个点后,需要子树外面存在坏点,且子树外面的好点在删除完子树后全都变坏。对于每个好点我们要求其子树外面的坏点全都在那个被删除的子树里。维护这些点的 lca,外加一个合并前后缀信息的树状数组即可。
加粗的部分是实现细节,别忘记了。
- \(^*\) [ABC275Ex] Monster
缺少了某些贪心直觉,希望只是短期内某些事情造成的。
我们声称问题的答案就是,对于每个 \(x \in [1,V]\),用线段将每个 \(a_i \ge x\) 的位置覆盖一次的最小代价的和。证明就是,考虑手画、调整一下,嗯嗯。
然后显然可以直接在笛卡尔树上做 ddp 状物。具体的,从大到小加入 \(a_i\),每个 \(f_i = \min(f_l + f_r + p_i,a_i)\),一定是最开始取前者,然后变成后者,只会发生一次。树剖线段树维护这个过程。很难写。
当然更高妙的做法是,仍然从大到小加入点,然后反悔贪心:每次找路径上最小的 \(b_i\),然后给整个路径减去 \(b_i\),意味着如果任意选择一个其它点就不需要花费这个 \(b_i\) 了。仍然树剖线段树维护,但是很好写。
前缀 \(\gcd\) 变化一定是除了一个数字,为了让数量最多,肯定会去除以 \(2,3\)(除以一个 \(5\) 的代价就可以除两个 \(2\))。
考虑从小到大去增加这个 \(\gcd\) 的值,每一次去乘以 \(2\) 或者 \(3\),设原本的是 \(g\),新的是 \(d\),那么我们往序列里插入所有 \(g\) 的倍数但是不是 \(d\) 的倍数的数字,方案数应当是 \(\binom{new-1}{old}\),其中 \(new = old + n/g - n/d\),再乘上 \((new - old)!\) 表示任意排列这些新插入的数字。复杂度线性。
不知道题解都在干啥。
一点思路也没有,然后就开始在没有人的机房里破防大叫,然后突然就会了啊!真的会因为这一瞬的茅塞顿开的感觉爱上 OI 的。哎哎。我要是还能再打几年 OI 该多好。【】就更好了。
首先考虑 \(a\) 是一个排列的情况。此时找到 \(\min\) 的全局最小值,其应当只出现了 \(1/2\) 次。从 \(\min\) 断开切成两个序列,现在我们知道这个序列的开头/末尾,可以立刻推出整个序列。
当 \(a\) 有重复的时候,很难通过直接分讨来选择走哪个。但是这个做法启发我们从值域上去考虑问题,或者说实际上是一个观察:相邻的两条限制 \((b_i,c_i),(b_{i+1},c_{i+1})\) 一定有一个相同的值 \(a_i\)。把序列 \(a\) 看作在值域上连续行走 \(n-1\) 次,每走一次需要一条 \((x,y)\) 的边,因此我们实际上是在寻找欧拉路径。离散化后把图建出来跑欧拉路径即可。一些细节:可能有 \(\min > \max\),此时无解;图不连通无解。
理性来说想到欧拉路径应当是刷大量题目堆出来的经验,但是秒掉这个题带给我的快感还是能让我短期内心情好很多的!
半年前我连这题都不会???6666666,埋了吧。
菜的顺序显然没有任何影响,人的顺序其实也没有影响。因此先把 \(a,b\) 排序,不难发现第一个 \(b_i < a_i\) 的位置就是答案。
放在值域线段树上,找第一个后缀和是负数的位置即可。
奇异搞笑题。为啥能 2k3 的,这不是 1k6?
套路地考虑前缀异或和,发现满足条件得划分点前缀异或和只能是 \(0\) 和 \(x\),且应当交替出现。进一步的,如果 \(pre_n \ne 0\),那 \(x = pre_n\),可以直接简单 dp,现在考虑 \(pre_n = 0\) 的情况。
设 \(dp_{x,0/1}\) 表示当前划分的 \(x\) 且末尾是否是 \(0\) 的方案数,遇到 \(pre_i \ne 0\) 则只会更新单点的 dp 值,但是遇到 \(pre_i = 0\) 会更新整个 dp 数组的 dp 值。解决办法也很经典:打 tag 延迟转移即可。
5 个月前我连这题都不会吗????
首先考虑 \(f(s)\) 的最小值怎么求。发现如果有一个字符只出现了一次,那么 \(f(s) = 0\),因为可以直接把这个字符放第一位;否则必然 \(f(s) \ge 1\)。
如果所有字符都一样那么 \(f(s) = n - 1\)。否则一定可以构造 \(\texttt{abbbbbbbaacdef}\) 这样的串,把所有的 \(\texttt{b}\) 都放在第一个 \(\texttt{a}\) 后面,这样后面不可能出现子串 \(\texttt{ab}\),因此 \(f(s) = 1\)。
现在需要解决字典序最小的问题。假设原字符串的字符集就是小写字母前 \(k\) 个。第一个字符肯定可以填 \(\texttt{a}\),考虑第二个如果要填 \(\texttt{a}\),那么后面就不能出现 \(\texttt{aa}\),只要隔着放就可以,因此要求 \(\texttt{a}\) 不是绝对众数。否则第二个字符填 \(\texttt{b}\)。如果字符串只有 \(\texttt{a,b}\) 两种字符,那么需要把所有 \(\texttt{b}\) 都一起填在这里,不然一定会有子串 \(\texttt{ab}\)。否则继续填 \(\texttt{a}\),填完 \(\texttt{a}\) 后填一个 \(\texttt{c}\) 隔开,然后剩下的再顺着填就行了。
糖糖哒。
设 \(f_{i,j}\) 是 \(i\) 天后初始气温是 \(j\) 的最终气温,显然 \(f_{i,j}\) 单调。
直接线段树二分找到区间后加减 \(1\) 即可。
点分树实在太难调了哦哦哦,还是写写树剖吧。
把 \(dis(u,v)\) 拆开,固定 \(u\) 时相当于要求 \(d_v - 2d_{lca}\) 的最小值。
于是设 \(f_l\) 表示 \(l\) 子树内的最小 \(l\) 值,但是使用的时候要除掉 \(u\) 子树这个方向。
那么套路地考虑树剖,将 \(f_l\) 的定义改成轻子树内的最值即可。
修改和查询都是简单的讨论。
首先可以求出一个数组 \(lim_i\) 表示位置 \(i\) 的值不能超过 \(lim_i\)。
然后我们还需要满足,每个区间 \([l,r]\) 内至少存在一个最大值 \(x\)。此时区间内不可能存在 \(lim_i > x\) 的位置。注意到 \(x\) 是互不相同的,直接从区间内 \(lim_i = x\) 的位置里随便选一个即可,选不了则无解。
然后问题就变成了经典问题:给定序列 \(lim\),要求构造序列 \(a\) 满足 \(a_i \le lim_i\) 且 \(a_1|a_2|\ldots|a_k|val\) 的值最大,其中 \(val\) 是已经确定了的位置的或和。按位贪心,某一位上如果至少有两个 \(1\) 则一个填 \(1\),一个填 \(0111111\ldots\),后面的所有位就都填满了。
这种题的一般做法是,考虑边缘确定后,整个矩阵就确定了。但是在这道题里这个限制还不够强。
考察如果某行连续出现了两个 \(1\),那么这两列一定都是 \(00/11/00/11\) 这样交替下去,然后两边的列也立刻全都确定。归纳得到,这个矩阵要么每一行都是 \(01\) 交替,要么每一列都是 \(01\) 交替。
计数就瞎几把数就行了。鉴定为大模拟。
第一眼看这个题毫无思路,完全不知道 \(q \cdot p\) 这种东西毫无处理。但是运用一些简单套路,将逆序对的贡献拆开,考虑如果 \(pos_i > pos_j\),那么 \((q_i,q_j)\) 在 \(r\) 里面是 \((q_j,q_i)\),即会在恰好 \(p,q\) 中的一个贡献。否则要么贡献 \(2\) 个要么贡献 \(0\) 个。
于是首先将读入的 \(p\) 转化为逆排列 \(pos\),\(k\) 的奇偶性需要和 \(pos\) 中的逆序对数 \(inv\) 相同,且 \(k \ge inv\)。然后就相当于需要让 \(q\) 中 \(pos_i < pos_j\) 的部分造成 \(k' = (k - inv) / 2\) 的贡献。即构造一个排列 \(q\),满足 \(i < j,pos_i < pos_j,q_i > q_j\) 的对 \((i,j)\) 恰好有 \(k'\) 个。
设 \(b_i\) 表示 \(i\) 后面 \(pos_j > pos_i\) 的位置 \(j\) 数量,从前到后扫描 \(i\)。如果 \(k' \ge b_i\) 就直接填最大值,否则找到第 \(k'\) 个 \(pos_j > pos_i\) 的位置,填 \([x,1,2,\ldots,x-1,x+1,\ldots,m]\) 即可,其中 \(x-1\) 对应第 \(k'\) 个位置。
复杂度瓶颈在求逆序对。
写一些序列 \(a\) 长什么样子,大概是 \([a_1,a_2,\ldots,a_n,a_1|a_2,a_2|a_3,\ldots,a_n|a_1|a_2,a_1|a_2|a_3,\ldots,a_{n-1}|a_{n}|a_1|a_2,\ldots]\)。发现从前到后依次是区间长度是 \(1,2,3,\ldots,n\) 的子区间的或和。
也就是说,对于每个询问,首先我们要求出最小的 \(len\) 满足存在一个长度为 \(len\) 的子区间使得其或和大于 \(x\),然后要求出最优的左端点。
注意到每个左端点只有 \(\mathcal O(\log V)\) 个本质不同的前缀或和,考虑按照 \(x\) 从小到大扫描线,线段树二分回答询问。复杂度 \(\mathcal O(n \log n \log V + q \log n)\)。
啊哦,哦啊。
考虑按位贪心,从大到小每一位,如果能把所有数字都调成 \(1\) 就调。复杂度 \(\mathcal O(nq)\)。
对于 hard version,注意到 \(a_i\) 很小,对于 \(j \ge 20\) 的位,整个序列在这一位上全都是 \(0\)。只要能变换一次,那所有数字都会变成 \(2^j\),后面的贡献容易计算。
否则就到了 \(j < 20\) 的位,此时需要把 \(a_i\) 在这一位上是 \(0\) 的数字找出来,计算它们的和和数量。如果代价不到 \(k\),那么就进行操作,此时所有是 \(0\) 的数的后 \(j\) 位都会变成 \(2^j\)。发现每次找出来的数字会要求若干位上必须是 \(1\) 且某一位上是 \(0\),可以直接高维前缀和统计。复杂度 \(\mathcal O(V \log^2 V + n + q \log V)\)。
高精度乘法和高精度开根已经很困难,不妨先取对数,将原式化为 \(\frac{\sum w_i}{c}\)。
平均数很难处理,那直接套一个经典的 01 分数规划,二分答案 \(mid\) 后将所有 \(w_i\) 减去 \(mid\),看答案能否大于 \(0\)。
在 AC 自动机上 DP 的复杂度是 \(\mathcal O(nm|\Sigma| \log v)\) 的,看起来过不了,但是确实能过,嗯嗯。
注意到从一个长方形边角扣下来格子不会改变周长,因此如果只需要求最小的周长 \(c\),可以将问题改写成,找到正整数 \(p,q\) 满足 \(pq \ge n\) 且 \(2(p+q)\) 最小。这是基础均值不等式,贪心的希望 \(p,q\) 尽可能接近。
\(u = 1\) 时构造方案非常简单,直接从第一行扣掉一些就行了。重点是怎么处理计数。
这里需要一点观察:最优解一定有 \(pq - n < \min(p,q)\),因为如果不满足这个,可以直接拿掉一整行或一整列,周长会更小。也就是说,不同的 \(p,q\) 的删去边角的方案不会算重。
对于一个 \(n\),最优的 \(p,q\) 只有 \(\mathcal O(\sqrt n)\) 个,原因是面积随着 \(p\) 的减小变化呈二次函数。考虑直接枚举 \(p,q\)。根据上述观察,四个角的删除是独立的,因为它们永远不会相交。
边角的删除形状必须是阶梯形,面积是 \(n\) 的阶梯数量可以简单 \(\mathcal O(n^2)\) DP 求出。由于 \(pq-n\) 也是 \(\mathcal O(\sqrt n)\) 级别的,可以预处理所有答案。
复杂度 \(\mathcal O(n+t \sqrt n)\)。
离谱,这不是 1900?
注意到对着一个大小为奇数的子树操作不会改变异或和,偶数会将异或和推平成 \(0\)。考虑设 \(dp_{u,i}\) 表示将子树 \(u\) 内的元素推平成 \(i\) 的方案数,直接背包转移即可。复杂度 \(\mathcal O(nv^2)\)。
输出方案就是模拟呗,纯糖。
鲜花:有人一开始没看到要最小化,想输出 \(1 \sim n\) 直接过 *2500。糖的要死。
通过交换将排列排序是经典问题,答案是 \(n\) 减去置换环数量,因为每个置换环只剩下一个元素时就不需要操作了。
当有两个排列时,一个位置不需要交换当且仅当它在两个排列里同时是最后一个元素。没有什么朴素的贪心策略,考虑建立网络流模型:给 \(a\) 的每个置换环向对应位置连边,每个位置向 \(b\) 的对应置换环连边,流量均为 \(1\)。答案就是 \(n\) 减去最大流。构造方案就直接把满流的 \((i,i+n)\) 拿出来,这些位置不操作就好了。
套路的用前缀异或和来刻画树上路径 XOR,题目中的限制即为 \(pre_i \oplus pre_j = x\),检查是否有解只需要建图跑一遍 dfs。
先给每个连通块的第一个元素都设置 \(pre_i = 0\)。拆位,考虑翻转一个 \(pre_i\) 会导致几个位置的 \(a_i\) 发生改变,记这个值为 \(cnt_i\)。如果 \(cnt_i\) 是奇数,那总可以通过这个 \(pre_i\) 的调整让全局 XOR 等于 \(0\)。
于是只需要找到一个 \(cnt_i\) 是奇数的位置。对每个连通块一起统计 \(cnt\) 即可,复杂度可以线性的吧。
考虑解决单组询问。由于油价只有两种,考虑这样一种贪心策略:在 \(b_i = 1\) 时直接加满,在 \(b_i = 2\) 时加到恰好 \(a_i\)。最后可能会剩下一些油,但根据我们的贪心策略,最后剩下的油一定是通过 \(b_i = 1\) 加的,代价直接减去即可。
注意 \(b_i = 1\) 时油会直接加满,从而基本进入了一个子问题。因此不妨 shift 序列使得一个 \(b_i = 1\) 的位置作为起点。一段从 \(i\) 出发回到 \(i\) 的旅程可以拆分为 \(i \to 1\) 和 \(1 \to i\)。注意后半段开始时一定会根据贪心在 \(1\) 位置加满油,因此起始油量对所有 \(i\) 都相同,线性扫一遍即可确定到每个 \(i\) 的代价 \(g_i\)。
考虑求解第一部分,令 \(f_i\) 表示 \(i \to n\) 的代价。记 \(pos\) 是 \(i\) 后面第一个 \(b_i = 1\) 的地方,则 \([i,pos)\) 这段路的代价 \(cost\) 可以前缀和 \(\mathcal O(1)\) 计算,直接 \(f_i = f_{pos} + cost\) 即可,复杂度仍然线性。
咋感觉这个做题笔记写的这么像入机,呃呃。
首先这个图是来搞笑的:既然每个点的度数都是 \(2\),那整个图一定是若干个环。
先考虑一个环怎么做。一定要注意到 \(l \ne r\)。此时先手操作完后环会断开成一条链。这是经典的对称构造例题:如果 \(n \ge l\),那后手可以从中间断开链,切成两个大小相等的短链。之后先手在一边动什么,后手就再另一侧做相同操作,如此先手必败。
因此一条链的胜负条件是 \(n \ge l\) 时(环上的)后手胜,否则先手胜。推出环上的胜负条件:\(n \in [l,l + r - 1]\) 时先手胜,否则后手胜。
现在来看多个环的情况,此时我们不仅需要胜负条件,还需要具体的 sg 值。先来看链上的 sg 值,注意由于 \(n > r\) 时后手必胜,sg 一定是 \(0\),因此 \(r\) 的限制是没有用的。容易写出一个 \(\mathcal O(n^2)\) 的 dp,观察后发现 \(sg_i = \lfloor \frac{i}{l} \rfloor\),证明应该不是太难。
那环的 sg 值就是一段区间的 mex,这个是好求的。复杂度线性。
观察:对于一个排列 \(p\),答案是 \(\sum p_i > i\)。
构造是很简单的,考虑直接沿着置换环顺着换,遇到一个反向边就从头开始。证明它是下界不难:一个 \(p_i > i\) 的位置必须需要重置才能放回去。
只有 \(2n\) 个本质不同的询问,全都预处理出来即可。大概形如一个二维数点,树状数组扫描线求解。
子序列的匹配问题直接贪心,考虑直接钦定 \(n\) 个数字在大序列里的出现位置,最后一个位置之前的空位置有 \(k-1\) 个可以填的数(不能形成匹配),但是最后一个后面可以随意。因此枚举最后一个位置 \(i\),式子是 \(\sum_i \binom{i-1}{n-1}(k-1)^{i-n}k^{m-i}\)。可以大力 gf 推出式子。
一个更牛的做法是容斥,用 \(k^m\) 减去所有不合法的序列。枚举匹配长度 \(i = 0 \sim n-1\),方案数是 \(\binom{m}{i}(k-1)^{m-i}\)。这样的精妙之处在于,把原本后面的系数 \(k\) 也统一成了 \(k-1\),方案数和最后一个位置 \(i\) 不再相关,使得答案式子变得很简洁。
组合数的计算是简单的。
- \(^*\) P7738 [NOI2021] 量子通信
OI 复健。
注意到 \(k_i \le 15\),考虑把原串分 \(|s|/16\) 块,则必定有一块完全匹配。因为数据随机,这一块匹配的串只有 \(\mathcal O(1)\) 个,暴力 bitset 比较即可。
- \(^*\) 模拟赛 T3
给定一棵 \(n\) 个点的树和排列 \(p\),持续执行操作直到所有点都被删除,在第 \(i\) 轮中,
- 如果 \(i\) 是奇数,那么删去每个连通块点权最小的点。
- 如果 \(i\) 是偶数,那么删去每个连通块点权最大的点。
问操作多少轮后树会被删空。\(n \le 3 \cdot 10^5\)。
糖糖糖。
先考虑链上怎么做:发现只需要 \(\mathcal O(1)\) 求出区间 rmq,那么暴力递归的复杂度就是线性。
扩展到树上,如果我们能用 \(\mathcal O(f)\) 的代价求出连通块的 rmq,那么复杂度将是 \(\mathcal O(nf)\)。
这个 bfs 的过程是很困难的,考虑转而去做 dfs。首先找到这个连通块的 rmq 点,然后先暴力递归它的儿子,其儿子的 rmq 仍然是一个子树。将这些做完后把子树内信息全部清空,再看根的子树就是原本子树补的信息。时间复杂度 \(\mathcal O(n \log n)\)。
- \(^*\) P6776 [NOI2020] 超现实树
神秘题。
我们想要从无限棵树里找一些比较有用的树进行判定。
定义一棵树是好的,当且仅当每个点的左右儿子至少有一个点的 \(siz \le 1\)。
一棵坏树一定不能生成好树,所有的坏树都可以由好树生成,这就意味着我们只需要判断是否存在大小无限的好树。
好树的形态一定是一条链上挂了一些点。一个点引出来的好树的形态只有四种,分别向下递归判断就好了。
感觉人类的语言很难描述这个东西。看看代码就懂了。
啊哦,哦啊。
容易想到哈希判断区间内是否每个数字出现次数都是 \(3\) 的倍数,但是我们要求出现次数恰好是 \(3\)。
这其实是在要求,区间内出现次数的 \(\max \le 3\),这是有单调性的,双指针维护。
哦啊,啊哦。
没有发现最关键的性质,但是没关系,我过啦!
首先注意到答案不超过 \(n\),因为把最低位都填成 \(1\) 就好了。
然后考虑先不进行操作,原图断裂成若干连通块。此时发现通过把末位改成 \(1\) 来连通数字是很优秀的,但是不是最优秀的。考虑全是一堆 \(2^k\),此时选最大的减 \(1\) 就可以连通。
注意减法操作只会进行一次,因此可以直接枚举是哪个位置,然后剩余的都 \(+1\)。复杂度 \(\mathcal O(n^2 \log V)\),其中 \(\mathcal O(n \log V)\) 是判断图的连通块。
更聪明的做法:注意到选择某一个最大的 lowbit 减去 \(1\) 后,此时如果还有相同 lowbit 剩余,就选择一个 \(+1\),此时图已经连通。因此答案不超过 \(2\)。暴力即可。
经典套路题了,上一道是这个做题笔记里的 loj3629。
每个条件只涉及两个变量,考虑一些匹配或是 2-sat 状物。稍加思考发现如果设置变量 \(v_{i,j} = [a_i \le j]\),每个限制条件可以转化为 \(m\) 个 2-sat 限制。直接跑就行了。
?啥几把,这不是橙题?
合法区间数量不超过 \(5n\) 个,单调栈求出即可。
- \(^*\) uoj61 【UR #5】怎样更有力气
哦啊。
首先应用经典结论:整张图的 MST 等价于将边集划分成若干子集,每个子集只保留 MST 后再求 MST 的结果。
那这道题里不难想到,我们将所有边划分成 \(m\) 个子集,每个子集里的边权全都相同,因此只需要找一棵生成树。\(p = 0\) 时直接选择原树边即可。对于每条树边,只需要保留最小的覆盖。
观察:如果某条路经上限制数量 \(lim < len - 1\),那么整个路径必然还连通,此时 MST 等价于取所有树边。因此只需要解决 \(lim \ge len -1\) 的 case,此时复杂度允许带上点数 \(n\) 了。这就是 CF1242B 0-1 MST:选择限制度数最小的点,连向其它所有边,剩余的跑暴力,复杂度是 \(\mathcal O(\min(\frac{m}{n},n)^2) = \mathcal O(n+m)\)。然后就做完了。
容易设计一个 dp:设 \(f_u\) 表示 \(u\) 到 \(n\) 的期望,\(f_u = 1 + \frac{1}{d}\sum \min(f_u,f_v)\)。
一个 trick 是,我们只关心 \(\le f_u\) 的 \(f_v\) 的具体值,因此可以按照 \(f_u\) 从小到大,类似最短路转移 DP。
对于一棵固定的生成树,边权和也是关于 \(t\) 的一次函数,因此显然取 \(t = l\) 或 \(r\) 时最优。
很困难的数数题。可能是没见过类似的 trick 导致的。
经典结论:\(n\) 个点的树的拓扑序数量是 \(\frac{n!}{\prod siz_i}\)。
拆贡献,枚举 \(i,j\) 计算最终拓扑序里 \(i,j\) 相邻的方案数。考虑合并节点 \(i,j\),构造一棵新树,使得 \(i,j\) 并成一个节点,且这个树的拓扑序数量和原图相等。
最简单的 case 是 \(i\) 是 \(j\) 的祖先,此时 \(i\) 只能是 \(j\) 的父亲。合并后会减少一个大小为 \(sz_j\) 的子树,且 \(1 \to i\) 的链上所有节点 \(sz_i\) 都减少 \(1\)。预处理 \(h_u\) 表示 \(u\) 的所有祖先的 \(\prod \frac{siz_u}{siz_u - 1}\) 即可。
剩下的 case 就是 \(i,j\) 并没有祖先关系。此时显然不能直接合并 \(i,j\),因为会多出来一些并不合法的拓扑序。令 \(d = \operatorname{lca}(i,j)\),我们强行将 \(fa_i \to d,fa_j \to d\) 两条链归并在一起,并把 \(i,j\) 一起挂在这个链的末端。这里归并的意思是构造一条新链,每次可以从 \(fa_i \to d\) 和 \(fa_j \to d\) 中的任意一条路径取一个点接上来。我们设 \(f_{i,j}\) 表示所有两条链归并方案的 \(\prod{1}{siz_i}\) 的变化量。考虑转移,转移枚举上一条链的末端到底是 \(fa_i\) 还是 \(fa_j\),以 \(fa_i\) 为例子,会少一个 \(siz_{fa_i}\) 的子树,多一个 \(siz_{fa_i} + siz_{j} - 1\) 的子树(\(-1\) 是因为 \(i,j\) 合并后子树内会少一个点),乘上来即可。
最终时间复杂度是 \(\mathcal O(n^2)\)。
WARNING:以下内容为口胡,未经过代码验证。
哈哈,我是高贵的口胡狗屎分讨选手。
首先注意到 \(1,2\) 间的互相操作相当于异或,而 \(0\) 和其它数字的操作相当于单点推平。我们先以 \(0\) 为分界点将序列切成若干段。
考虑哪些情况下我们可以让答案是 \(1\):
- 如果有一段序列有偶数个 \(2\),那我们可以利用两边的 \(0\) 将除了这一段以外的地方全部推成 \(1\),最终答案为 \(1\)。
- 有一段有大于等于 \(3\) 个 \(2\)。可以这样操作:\([2,2,2,0] \to [2,1,0] \to [2,1]\),这样这一段和后面一段拼接后就有了偶数个 \(2\),条件一达成。
- \(0\) 旁边有 \(1\)。此时直接消掉 \(0\),条件一达成。
因此,如果出现了 \(0\),那么最终答案为 \(2\) 的序列形态只能是 \(\textbf{[1,1,1,\ldots,1,2,0,2,1,1,\ldots]}\)。
那很自然的想到直接分讨来求这个最小的字典序,唯一的问题是太太太太难写了。
考虑另一种套路的求字典序的方法,按位贪心。由上面的过程发现第 \(i\) 次操作不会操作 \(\ge 4\) 的位置,直接维护子串 \([2,0,2],[1,2],[2,1]\) 的数量和 \(0\) 的即可。 复杂度可能是线性。
-
感性理解复杂度挺对的。
-
CF1109C Sasha and a Patient Friend \(\color{ff0000}2800\)
考虑把时间轴分成若干个速度的连续区间,一个操作一相当于新增一个段。把每个段可以走的距离挂在区间左端点上。一次查询时,两边的散段可以直接计算,中间的整段可以在线段树上二分。删除用线段树分治改写为撤销即可。
- \(^*\) CF1648F Two Avenues
我们只能选择两条边,因此如果两个点在一个边三连通分量里,它们的最短路将始终是 \(0\)。对原图边三缩点,缩完后形成一颗边仙人掌。问题转化到这个仙人掌上。
我们要么在同一个环上断两条边,要么断开两条非环边。后者的贡献可以直接差分统计。
考虑在一个环上断两条边的情况。先将给定的 \(m\) 个点对在这个环上的部分找出来,然后选择两条边的代价就是和这两条边的连线相交的路径数量。顺序枚举第一条边,我们断言第二条边的选择有决策单调性,可以主席树维护二维数点,决策单调性分治完成。
我们不能对每个环都暴力枚举 \(m\) 个点对。但是注意到如果建出仙人掌的圆方树,一条路径只有在一个环上不是儿子往父亲方向的路径。特判 LCA 处后差分统计数量即可。
看起来非常难写,/tuu。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战