转存的 2025 赛季训练

这里是 2024 - 2025 赛季的训练。

P2519

妙。考虑转化条件。对于一个 \(a_i,b_i\),转化成分数从大到小排序后编号在 \([a_i+1,n-b_i]\) 的人的分数相等。

那么我们可以得到若干个 \([l,r]\),在这些 \([l,r]\) 中取尽量多的,互不相交的即可。dp 解决。

P2516

被打爆了。首先把 \(f_{i,j}\) 表示 \(A_{1\sim i}\)\(B_{1,j}\) 的 LCS 跑出来。然后记 \(g_{i,j}\) 为方案数。考虑转移:

  • \(f_{i,j} = f_{i-1,j}\)。此时 \(A_i\) 不在 LCS 中。\(g_{i,j} = g_{i-1,j}\)
  • \(f_{i,j} = f_{i,j-1}\)。此时 \(B_j\) 不在 LCS 中。\(g_{i,j} = g_{i,j-1}\)
  • \(f_{i,j} = f_{i-1,j-1}\)。此时 \(A_i,B_j\) 在 LCS 中。\(g_{i,j} = g_{i-1,j-1}\)

上述相加即可。但是考虑 \(A_i \ne B_j\)\(f_{i-1,j}=f_{i,j-1}=f_{i-1,j-1}\) 的情况,此时 \(g_{i-1,j-1}\) 被算了两次。减去即可。

注意要滚动数组。

P2051

喜欢给极小的样例还不给大样例的出题人你们好啊。

显然每行、列的炮至多有 \(2\) 个。

50pts 可以考虑状压,这是典中典了。

考虑把炮的个数压入状态。\(f_{i,j,k}\) 表示前 \(i\) 行,\(j\) 列放了一个炮,\(k\) 列放了两个炮。

分讨第 \(i\) 行放了 \(0/1/2\) 个炮讨论即可。

CF149D

好区间 dp。

显然的区间 dp。首先由于保证是一个合法的括号序列,这启发我们 dp 时每次分割成两个合法区间,再进行 dp。

那么每次可以分割成两个合法的区间。当 \((l,r)\) 配对时,特殊处理一下方案数。

使用记搜实现。

P10680

st 表好题。

首先注意到这个神秘的 \([l,l+2^k-1]\) 以及这个神秘的合并操作,启发我们使用 st 表。原因是 st 表可以高效合并两个一半区间。

不带修就是 st 表板子。带修捏?

首先要明确的是 st 表单点修改一次重构是 \(\mathcal{O(n)}\) 的。具体是因为单点影响的范围极小。

考虑阈值分治。对于 \(st_{i,k}\)\(k\) 较小的部分,暴力重构。在查询时,暴力从两个子区间合并即可。

可以证明阈值 \(B = 10\),时间复杂度 \(\mathcal{O(n\sqrt n)}\)。具体不会证。

P10334

小清新贪心。

先把无解判掉。

正着做不太好做,考虑倒着枚举时间。

显然对于某个时刻,它的一些需求可能需要在前面的时刻制作。

我们维护一个栈来存放当前的需求。假设对于当前这个 \(t_i\),后面还有一些需求 \(a_x\) 没有完成,那么当前这个位置的需求 \(a_i\) 需要 \(\ge \max\{a_x\}\)。否则第 \(i\) 个人来就不会取 \(a_i\) 而是 \(\max\{a_x\}\)\(a_x\) 是要留给后面的,必然存在),后面你再去制作 \(a_x\) 的话代价就更大了。这一部分需要好好理解。

那么对于某个 \(t_i\),它的需求就是 \(\max(A_i, \max\{A_x\})\)。后者可以用栈来维护。

那么对于我们现在的 \(t_i\),共有 \(t_{i+1} - t_i\) 个时刻给我们完成后面的需求。每次取出栈顶即可。原因是栈中尽量大的数要尽量早出来,不然它留在栈顶在前面会影响更多 \(A\)。感性理解一下。

那么做完啦。很多人认为这是单调栈。但笔者认为这只是具有单调性质的栈罢了。时间复杂度线性。

ARC201C

Sol

P1600

好但是唐题啊。

前 60pts 很唐。

考虑所有 \(t_i = 1\) 的情况。实际上不难想,难点在于维护。有个 trick 由于我们只关心某一项的值。子树内的答案是更新后的减去原来的。

考虑正解。记 \(dep_x\) 表示根节点到 \(x\) 的边数。对于一条路径 \((s,t)\),将其拆分为 \((s,lca)\)\((lca,t)\)。那么 \((s,lca)\) 上某个点 \(u\) 若有贡献当且仅当 \(dep_s = dep_u + W_u\)。同理 \((lca,t)\) 上点 \(u\) 有贡献当且仅当 \(dep_{lca} \times 2 + dep_s = dep_u - W_u\)

观察到等式左边为定值。那么对于每个 \(u\),计算它子树内有多少条路径满足即可。具体可以树上差分。然后动态维护当前有多少 \(dep_s = W_u\)\(dep_{lca} \times 2 + dep_s = dep_u - W_u\)。这一部分是容易的。但是可能会算重。容易证明重复的只有根节点,也就是某条路径可能被根节点算两次。因此树上差分时只加一边就好了。

\(\mathcal{O(n\log n)}\)

P4170

怎么区间 dp 这么难。

考虑区间 dp。\(F_{i,j}\) 表示 \([i,j]\) 已满足条件的最小答案。

转移显然考虑枚举断点 \(k\),用 \(F_{i,k}+F_{k+1,j}\) 去更新。

\(S_i = S_j\) 时,显然可以找到前面某次对 \(i\) 染色的操作 \((i,x)\),考虑将 \(x \leftarrow j\),并将这次操作挪到最后,容易证明原序列不变且操作次数不变。所以可以用 \(F_{i,j-1}\) 来转移。

ABC424D

Sol

ABC424E

弘文了。

考虑朴素暴力。考虑优化。注意到我们对同一元素进行了太多重复操作。于是把元素的个数同时压进优先队列。那么做完了。由于一个数的分裂会很快。

注意不能清空堆。空间换时间,每次新开一个。

ABC424F

天天犯唐。

线段树的做法有些难想。考虑哈希。每次把 \([A,B]\) 随机一个权值,把 \([A,B]\) 区间异或上这个权值。那么两个点的权值相同当且仅当覆盖它们的线段集合相同,那么每次单点判断即可。

区间异或、单点修改。线段树随便维护。

P1272

树形 dp 怎么这么难。

明确一下状态:\(F_{i,j,k}\) 表示以 \(i\) 为根,且此时 \(i\) 与父节点相连,考虑 \(i\) 的前 \(k\) 个儿子在子树内得到 \(j\) 个点需割掉的最少的边。

考虑转移。考虑 \(u \to v\)。若 \(v\) 子树内不取,\(F_{u,j,k} = F_{u,j,k-1} + 1\)。即把其割掉。

否则枚举给 \(v\) 子树 \(s\) 个。\(F_{u,j,k} = \min\{F_{u,j - s, k-1} + F_{v,j_v,k-1}\}\)。显然 \(k\) 可以滚掉。

需要注意的是,我们需要强制选根。不然就不能把那些选的子树连接起来。因此对于非根节点。由于我们强制选根,那么需要把根和父亲这条边断开。因此答案再统计时要加 \(1\)

P6033

遇到这种题,先考虑部分分。

朴素是带 log 的,考虑怎么做到线性。

我们用一个 蚯蚓 中的 trick。就是你合并之后一定是越来越大的,具有单调性。这个比蚯蚓那题的证明简单多了。

所以类似地,单独开一个数组来合并的结果,由于两边都是单调的每次只拿出队头作比较即可。

话说好像是这题的结论推广到蚯蚓那的吧?

P14072

热恋。

dp 好题。

假设我们将原排列分成两个大小为 \(n\) 的集合 \(A,B\)。由于 \(k \le 2n\)\(A\)\(B\) 中必然有一个包含 \(k\),那么此时这个集合中数的乘积必然是 \(k\) 的倍数。也就是说,此时另一个集合中数的乘积也要求是 \(k\) 的倍数。

那么问题转化为,从原排列中选出 \(n\) 个数,要求不含 \(k\) 且其乘积为 \(k\) 的倍数。不妨从小到大选。记其方案数为 \(d\),那么答案就是 \(d \times 2 \times n! \times n!\)。这个是好理解的。

那么可以 dp 了。\(F_{i,j,l}\) 表示前 \(i\) 个数,选了 \(j\) 个,当前选出来的数之积对 \(k\) 取模为 \(l\) 的方案数。这样很好转移。分讨每个数选 or 不选。不选就是 \(F_{i,j,l} \leftarrow F_{i-1,j-1,l}\)。选的话就是 \(F_{i,j,(l \times i) \bmod k} \leftarrow F_{i,j,(l \times i) \bmod k} + F_{i-1,j-1,l}\)。那么做到 \(\mathcal{O(n^3)}\)。值得注意的是,一个数都没选时默认积为 \(1\),故边界为 \(F_{0,0,1} = 1\)

咋优化捏?由于我们只关心是否是 \(k\) 的倍数,状态放余数有些浪费了。那么就记最大公约数!\(F_{i,j,l}\) 表示前 \(i\) 个数,选了 \(j\) 个,当前乘积与 \(k\) 的最大公约数为 \(l\) 的方案数。那么转移是类似的。但是有个难点,就是假设当前的最大公约数是 \(x\),怎么得到选上 \(i\) 后的最大公约数呢?这个手玩一下可以得到是 \(x \times \gcd(i,k/x)\)。还是比较好算的。那么预处理最大公约数,我们得到了 \(\mathcal{O(n^2\log n + n^2d(k))}\),其中 \(d(k)\) 表示 \(k\) 的因子个数。可以本地算一下 \(k = 2000\)\(d(k) \le 64\)。得益于洛谷飞快的评测机,可以通过。

你会发现这样写出来会被卡一个点。这时需要卡卡常。把状态里第三维换为 \(k\) 的第 \(l\) 个因子即可。这样可以通过。

code

CF547B

手刃了。

考虑每个位置能影响到的两个端点。即对于 \(i\),左边最后一个不小于它的位置 \(L\),右边最后一个不小于它的位置 \(R\)。那么对于长度 \([1,R-L+1]\)\(i\) 都有贡献。

\(L,R\) 显然可以用单调栈维护。然后后面那个前缀最大值的话修改右端点就好了。差点爆了个 sgt 上去。

CF1407D

红温了。

显然的 dp。

先考虑第二种情况。这里假设考虑到 \(i\) 节点,正在寻找 \(j\) 去转移。注意到右边是 \(\min\),于是分讨 \(h_j,h_i\) 的大小关系。

  • \(h_j < h_i\)。此时 \(\min = h_j\),也就是说,\(\max\{a_{j+1},\cdots c_{i-1}\} < h_j\)。那么维护一个自底到顶单调递减的栈,容易发现在用 \(i\) 维护栈时,弹出的恰好是满足条件的 \(j\) 节点。
  • \(h_j \ge h_i\)。此时显然只有 \(i\) 前第一个 \(\ge h_i\)\(h_j\) 可以被更新。

第三种情况与第二种情况类似。于是开两个栈解决问题。

但是要注意处理相同元素。具体地,以第二种情况为例,每次在弹出时,我们需要在保证弹出的这个位置 \(x\)\(i\) 所有元素不相同,这样才可以从 \(x - 1\) 转移。

ABC352D

不会做小黄题。

考虑枚举连续的 \(k\) 个数。那么对于这 \(k\) 个数,答案就是数之中最大出现位置 - 最小出现位置。ds 维护即可。

CF1195E

先得把 P2216 过了。这两题一样的。就是 \(C_{i,j}\) 表示第 \(i\) 行,\([j,j+b-1]\)\(A_{i,j}\)\(\min\)。然后在 \(C\) 上以列做一遍就好了。

交上去 mle 还以为卡 deque。虚空调试 0.5h 发现删掉几个没用的数组就过了。唐完了。

P1080

怎么以前做的题现在不会了 /fn

显然的贪心。考虑对于数对 \((a_i,b_i),(a_j,b_j)\),那么如果交换后更劣的话,有 \(\max\{\frac{1}{b_i},\frac{a_i}{b_j}\ < \max\{\frac{1}{b_j},\frac{a_j}{b_i}\}\)。拆掉式子就变成 \(a_ib_i < a_jb_j\),排序即可。

CF1142B

好题啊。

由于是 \(A\) 的子序列,不要求连续。考虑每个 \(i\) 作为起点,每次往后跳,若能跳 \(n-1\) 次,则这个起点可行。

然后上述过程是可以倍增维护的。对于每个 \(i\),它跳完有一个最小位置 \(B_i\)。那么每个询问查询 \([L,R]\)\(B_i\)\(\min\) 即可,如果 \(\le R\) 就可行。

注意如果不能跳 \(B_i\) 要赋值为 \(m+1\)

因为 UB 调了快 1h,我是奶龙。

CF1848F

Fun fact:正解是手模四次操作发现规律。做的时候手模三次没发现规律就跑路了。iee

考虑手模样例。你会发现在第 \(2^p\) 次操作时,\(A_i = A_i \oplus A_{i+2^p}\)。这是固定的。

由于序列全 \(0\) 后你再操作也没啥影响。于是按位贪心,每次判断 \(2^p\) 次操作是不是有必要的。然后维护 \(A\) 即可。

CF1903D1

水掉了。

考虑按位贪心。每一位是否能取,那么 \(\mathcal{O(n)}\) 计算贡献即可。时间复杂度 \(\mathcal{O(qn\log n)}\)。能过。

D2 的话就是瓶颈在于计算贡献。那么考虑 SOSDP。不太会跑路了。

CF932D

由于前加入的点不会影响后加入的点,可以预处理。

每个 \(i\) 在往上跳时只会对应一个 \(j\),所以考虑倍增。

倍增维护每个点往上跳 \(2^i\) 步到达的点,路径上的最值。这样可以求出每个 \(i\) 对应的那个唯一合法的 \(j\)

然后将 \(j,i\) 建边。再进行一次倍增,这样每次询问时跳就好了。还需要维护路径的长度以及点权和。

注意比较恶心的是这题是点权,所以在查询跳的时候 \(x+2^i\) 是不取的。这样你 \(x \leftarrow x+2^i\),就不会重复计算。因此你可能跳到 \(0\) 也是合法的。

P7143

神秘分治题。

考虑分治。容易发现答案只与长度有关。记 \(F_n\) 表示长度为 \(n\) 的答案。考虑区间 \([l,r]\) 怎么贡献。

  • 两个端点都在 \([l,mid]\)\([mid+1,r]\) 中。显然这是子问题,分治下去即可。
  • 两个端点分别在 \([l,mid]\)\([mid + 1, r]\) 中。首先由于除 \([1,n]\)\(mid\)\(mid+1\) 一定不在同一区间内。因此对于区间 \([x,y]\),覆盖的区间一定是形如 \([x,mid]\) 的关于 \(mid\) 的后缀 和形如 \([mid+1,y]\) 的关于 \(mid+1\) 的前缀。那么统计出 \([x,mid]\) 的后缀 cover 和 \(s_1\),贡献即为 \(s_1 \times [y - (mid + 1) + 1]\)。同理右边的前缀 cover 和 \(s_2\),贡献就是 \(s_2 \times (mid - x + 1)\)

P11005

我是唐氏。

\(f(u,v) = x\) 等价于 \(u,v\) 只能通过边权 \(\ge x\) 的边连通。从小到大加边即可。

P2048

典题现在才做。

暴力的做法是把所有区间塞进堆然后取 \(k\) 次。但是这样会爆。考虑一个很牛逼的 trick。

由于我们只关心前 \(k\) 大,我们是不是能从当前的某个答案,推出下一个合法的答案,再塞入堆呢?记 \((v,p,l,r,x)\) 表示当前答案最大值为 \(v\),取到的位置为 \(p\),以 \(x\) 为右端点,在 \([l, r]\) 中转移。那么每次取出最大的 \(v\),就可以分裂出两个合法的答案 \((v',p',l,p-1,x)\)\((v'',p'',p+1,r,x)\)。塞入堆中再维护即可。

P3801

容斥好题。

如果你把释放的位置也看做消失的话,那么假设当前范围内有 \(p\) 行被染色,\(q\) 列被染了,就好恰好有 \(p*q\) 个格子重复染了(也就是消失了)。那么做完了。

P8473

不会做糖糖题。

首先每次加入的那一堆线段很烦,考虑啥是有用的,你会发现区间内相隔最远的两个黑点才是有用的,因为这两个黑点间所有点都能被染黑。因此每次加入一个区间,只考虑其间距离最远的两个黑点,将这段区间覆盖即可。每次询问等价于询问是否有白点没有被覆盖。这个用 sgt 维护区间 \(+/- 1\) 即可。

P9691

咋这么难。

首先如果代价为 \(1\) 的话就是超速检测。这里借鉴一下思路。\(F_i\) 表示前 \(i\) 个点,第 \(i\) 个点一定选的最小代价。

考虑 \(i\) 可以从哪转移过来。假设从 \(j\) 转移过来,那么需要满足 \((j,i)\) 中没有完整的区间,这个很好理解。那么对于每个 \(i\),记 \(p_i\) 表示最小的满足条件的 \(j\),这个显然是满足区间右端点 \(<i\) 的左端点最大值,很好维护。那么 \(i\) 就可以从 \((p_i,i)\) 中转移。偷懒写了 sgt,实际上有单调性的。

P8026

不可以总司令。

由于我们只关心两个点是否联通,等价于它们的各个祖先是否相等。于是给每个图赋一个随机值,哈希记录每张图上每个点的祖先之和的哈希值。判断两点祖先是否相等就等价于判断两点哈希值是否相同。

更具体地,记每张图的哈希值为 \(S_i\),假设第 \(i\) 张图的点 \(j\) 的一个祖先为 \(k\)\(j\) 的哈希值就加上 \(S_i * k\)。正确性显然。注意连边时,维护祖先要使用启发式合并。

P3792

bbwzt

异或哈希板子。对于询问,可以根据区间和判断这个区间本应该是啥,然后异或哈希判断即可。

P2536

考虑朴素 dp。每次对于一个文本串,一个模式串进行判断。\(f_{i,j}\) 表示模式串 \(S\) 的前 \(i\) 位,文本串 \(T\) 的前 \(j\) 位能否进行匹配。

分讨 \(S_i\)

  • 为字母。平凡。
  • \(?\)。显然只关心 \(f_{i-1,j-1}\)
  • \(*\)。不贡献:\(f_{i-1,j}\)。贡献 \(1\) 位:\(f_{i-1,j-1}\)。贡献若干位:\(f_{i-1,k}\)

这样是 \(\mathcal{O(nmL^2)}\) 的。

考虑当 \(*\) 贡献若干位的时候,实际上可以看成是 \(f_{i,j-1}\),仔细想想就发现这是对的了,这也是一个 trick。这样还是 \(\mathcal{O(nmL)}\) 的,但是已经过题了。

考虑用 trie 优化。先把所有文本串扔进 trie。然后我们用模式串进行匹配。匹配的过程和上面的 dp 是一样的,最终只要统计能走到多少个文本串的末尾就好了,注意要判重。

P1944

小黄题这么难。

\(f_i\) 表示以 \(i\) 为结尾的最长连续合法括号序列。那么如果 \(S_i = S_{i-1-f_{i-1}}\),就有转移 \(f_i = f_{i-1} + 2 + f_{i-2-f_{i-1}}\)

这个太难想了!不妨求出每个括号是否能被合法匹配,记其为 \(h_i\),这个很好求。那么问题转化为求 \(h_i\) 中最长连续 \(1\) 数量。简单做即可。

P6286

怎么是板子。

考虑直接按加密后字符串顺序排序,那么假设我们有 \(S,T\) 要满足 \(S\)\(T\) 前面,显然只需要满足 \(S\) 最高一位与 \(T\) 不一样的小于 \(T\) 就好了。那么我们就会得到若干条形如 \(x\) 要在 \(y\) 前面的性质,考虑直接连边跑拓扑,有环则无解。做完了。

CF1879D

先做 P3917。那题可以先对 \(A\) 异或一遍前缀,即 \(A_i = A_1\oplus A_2 \oplus \cdots A_i\)。下文中 \(A_i\) 表示异或后的 \(A_i\)。那么按位考虑,思考每一位咋选才能有贡献。实际上,不妨记 \(B_i\) 表示 \(A_i\) 的第 \(x\) 位。那么由于异或可以用类似前缀和来维护,那么 \(B_i\) 中的每个 \(1\) 都可以和 \(0\) 匹配(不管是往前还是往后)。那么那题就做完了。

这题的话也差不多,用 \(0\) 去匹配 \(1\),分别维护前缀 / 后缀中 \(1\) 的下标和即可。

P5662

做不来普及组的题,玉玉了。

考虑一个很妙的性质:假设你在第 \(x\) 天买入,第 \(y\) 天卖出某个商品。那么等价于在第 \(x\) 天买入,第 \(x+1\) 天卖出,第 \(x+1\) 天买入,第 \(x+2\) 天卖出 \(\cdots\)\(y-1\) 天买入,第 \(y\) 天卖出。那么第 \(i\) 天买的东西不妨强制第 \(i+1\) 天卖出。

这样第 \(i\) 天的金币数就只跟第 \(i-1\) 天的金币数有关了。对于第 \(i\) 天,只需要贪心地让第 \(i\) 天买入的商品在第 \(i+1\) 天卖出的利润尽量大就好了。对于每一天分别 dp 就好了。

P11323

又被普及组贪心击杀了。

将炸看成三带一。那么尽量出四张肯定最优。于是用单 / 双张去凑三张即可。做完了。

ABC379F

又被击杀了。

考虑离线下来,按 \(l\) 排序。

对于一栋建筑 \(x\),显然如果它能被 \(l\) 看到,一定能被 \(r\) 看到。

于是维护 \(l\) 右侧能看到的建筑,这个可以用单调栈维护。然后在栈上二分 \(r\) 能看到的即可。

口胡了没写。

P1419

不会普及组 trick。

考虑二分答案。然后你就会了。

P13271

击杀了。

分层图板子。一个 naive 的想法是每个点建 \(k\) 个状态,但是会爆。注意到 \(\sum d_i = m\),由于每个点只有 \(d_i\) 个状态有用,于是只建 \(d_i\) 个。

\((u,p)\) 表示 \(u\) 点的第 \(p\) 个状态。对于边 \(u\to v\),且这条是 \(u\) 的第 \(l\) 条边。如果 \(d_v \ge l\),显然可以直接连 \((u,l) \to (v,l)\)。反之,只能 \((u,l) \to (v,d_v)\) 连,且需要维护 \(l \to d_v\) 的代价,前缀和维护。

然后跑最短路。但是你发现这样有个问题,对于某些没有出边的点,我们貌似强制它的最终状态为 \(1\) 的,这是不对的。考虑建反图。在计算 \(x\) 的答案时,枚举所有指向 \(x\) 的点 \(u\),即在原来的图中 \(u \to x\),假设这是第 \(l\) 条边,边权为 \(w\)。用 \(dis_{u,l}+w\) 来更新答案即可。做完了。

P6492

模板题。被击杀了。

考虑 sgt 维护每个节点的前 / 后缀,区间内最大值。然后就是小白逛公园。类似那题多维护的一个 \(sum\),这里需要判断前缀是否为本身。pushup 是这样的:

void pushup(ll k, ll l, ll r)
{
	ll mid = l + r >> 1;
	ll L = mid - l + 1, R = r - mid; 
	if (A[mid] != A[mid + 1])
	{
		if (tc[k << 1].Ls == L) tc[k].Ls = L + tc[k << 1 | 1].Ls; 
		else tc[k].Ls = tc[k << 1].Ls; 
		
		if (tc[k << 1 | 1].Rs == R) tc[k].Rs = tc[k << 1].Rs + R; 
		else tc[k].Rs = tc[k << 1 | 1].Rs; 
		
		tc[k].Ans = max(tc[k << 1].Ans, tc[k << 1 | 1].Ans);
		tc[k].Ans = max(tc[k].Ans, tc[k << 1].Rs + tc[k << 1 | 1].Ls);
	}
	else
	{
		tc[k].Ls = tc[k << 1].Ls; 
		tc[k].Rs = tc[k << 1 | 1].Rs; 
		tc[k].Ans = max(tc[k << 1].Ans, tc[k << 1 | 1].Ans);
	}
}

P4198

典题。

显然要考虑斜率。问题转化为单点修改,查询全局最长上升子序列的长度。

对于每个节点,我们维护它区间内的斜率最大值 \(k\),和区间内的答案 \(L\)。在自下而上合并时 \(k\) 很好维护,问题在于 \(L\) 的合并。

显然对于节点 \(x\),它的左儿子的答案可以直接合并。右儿子的话需要我们找到第一个 \(>\) 左儿子的 \(k\)\(\max\) 的点 \(p\),将 \(p\) 后面的答案接上。

\(get(l,r,k)\) 表示 \([l,r]\) 内第一个 \(>k\) 的位置开始的序列长度。那么上面 \(x\) 就可以从左儿子的 \(L\) 和右儿子的 get 合并。现在只需要解决 \(get(l,r,k)\)。分讨状态:

  • 当前为叶子,平凡。
  • \([l,r]\) 中斜率的最大值 \(\le k\),答案显然为 \(0\)
  • \([l,mid]\) 中斜率的最大值 \(> k\),此时 \((mid,r]\) 中的答案必定可行,只需在 \([l,mid]\) 中继续查询。但是注意右儿子的答案需要用 \([l,r]\)\(L\) 减去 \([l,mid]\)\(L\) 来得到。
  • \([l,mid]\) 的斜率的最大值 \(\le k\),此时只需在 \((mid,r]\) 中继续查询。
ll get(ll k, ll l, ll r, ld v)
{
	ll mid = l + r >> 1;
	if (l == r) return tc[k].mx > v; 
	if (tc[k].mx <= v) return 0; 
	if (tc[k << 1].mx > v) return get(k << 1, l, mid, v) + tc[k].len - tc[k << 1].len; 
	return get(k << 1 | 1, mid + 1, r, v);
}
void pushup(ll k, ll l, ll r)
{
	ll mid = l + r >> 1;
	tc[k].mx = max(tc[k << 1].mx, tc[k << 1 | 1].mx);
	tc[k].len = tc[k << 1].len + get(k << 1 | 1, mid + 1, r, tc[k << 1].mx);
}

那么做完了。是 2log 的。

ARC119C

结论题。

操作 \(1\) 无用。手摸一下可以发现一个区间合法当且仅当其交错和为 \(0\),那么将奇数位不变,偶数位 \(\times (-1)\),问题转化为区间和为 \(0\) 的区间个数,简单维护。

P7073

诗人?

用栈来维护,先把表达式树建出来。

由于每次只修改一个点,考虑这个点啥时候对答案有影响?

对于类似 0&01|1 这种东西,由于只修改一个点,可以发现无论左右咋变,答案都不变。

那对于这种东西,把它子树内的变量标记为没用的点即可。

实际上要标记的是有用的点。显然。

对于那些对答案有影响的点,容易证明它一定会让答案发生改变,不会出现不变的现象。那么搞定了。

P8815

不会中缀转后缀。

  • 左括号直接入栈。
  • 右括号,不断弹栈直到弹出左括号。
  • 数字直接入栈。
  • 操作符,不断弹栈直到栈空或者弹到优先级比它高的字符。

转完后遍历一遍就做完了。

P10115

很典但是把我击杀了的题。

\(f_i\) 表示前 \(i\) 位的答案。枚举当前段的上一个位置 \(j\)。如果 \([j,i]\) 合法就更新 \(f_i = \max\{f_{j-1} + w_i - w_j\}\),否则 \(f_i = \max\{f_{j-1}\}\)。那么做到二次方。

注意到第二项不用枚举。瓶颈在于第一项。把 \(j\) 提出来,\(f_i = \max\{f_{j-1} - w_j\} + w_i\)。其中 \([j,i]\) 要合法,考虑怎么快速维护这个东西。

\(c_i\) 表示 \(\max\{f_{j-1} - w_j\}\)。对于右括号,匹配出它对应的左括号,不妨令其为 \(p\)。那么 \(c_i = \max\{c_{p-1}, f_{p-1} - w_p\}\)。还是很显然的。那么做完了。用 stl 会带一只 log。

P8848

钛合金手机。中间忘了,后面忘了。

首先与 A 类似地,\(p,q\) 分别表示 \(1,-1\) 个数。

\(p \le q\) 最大子段和为 \(1\)。在 \(-1\) 中插 \(1\) 即可。\(\binom{q+1}{p}\)

否则,考虑 dp。由于我们要让答案取到下界 \(p - q\),容易证明每个 \(-1\) 必定在两个 \(1\) 之间。那么当前的前缀和就是最大子段和。于是可以 dp。\(f_{i,j}\) 表示用了 \(i\)\(1\),前缀和为 \(j\) 的方案数,很好转移。滚动一下数组就是 \(\mathcal{O(n^2)}\) 的,但常数很小。

P14083

感觉挺简单的。但还是被击杀了。

首先明确 \(f(i)\) 表示 \(i\) 在第几层括号里。其实这个知道也没啥用,方便理解。

先判断 \(p\) 是左括号还是右括号,只需判断 \(p - f(p)\) 的奇偶性即可。这个很好证明,打表也可以发现。

然后假设 \(p\) 是左括号,令其配对的括号为 \(q\)。可以发现 \(p+1\sim q\) 单调不增。那么二分,做完了。

注意判断 \(r-l=1\) 的时候,这样少一次,可以通过。

P11470

没写口胡了一下。

注意到 \(\sum x_i\) 的神秘限制。考虑 \(f_i\) 表示 \(\sum x = i\) 时,\(\sum y\) 的最大值。挺套路。

那么每组询问可以枚举 \(i\),答案就是 \(\min\{a + i,b+f_i\}\)。这样会爆。

考虑二分答案。假设答案为 \(x\)。那么有

\(a+i \ge x, b+f_i \ge x\)

也就是

\(i \ge x - a\)\(f_i \ge x - b\)

右边都是定值。那么只需维护 \([x-a,V]\)\(f_i\) 的最大值是否 \(\ge x - b\) 即可。后缀和可以维护。

P9742

又被贪心创飞了。

考虑序列中第一个负数到最后一个正数,显然可以调整使得每一个人都达到正贡献。

考虑一个非负数的连续段 \([l,r]\),我们会牺牲某个人 \(i\) 的代价,让 \(i \leftarrow r\),这样 \([i+1,r]\) 就有贡献了。枚举 \(i\) 取最值即可做到线性。非正数同理。那么做完了。

P11230

首先考虑如果能从一个人转移咋做。显然考虑 \(f_{r,x}\) 表示第 \(r\)\(x\) 号元素能否做最后一个。

转移的时候,枚举每个 \(i\) 的词典,假设到了 \(x = d_{i,j}\)。那么判断 \(p \in [j-k+1,j-1]\) 中是否有 \(f_{r-1,d_{i,p}} = 1\) 即可。

考虑这个限制。现在我们不仅关心能不能做,我们还要关心它是从哪一行转移的。

\(f_{r,x} = 0/x/-1\) 表示能被两行以上转移,只能被第 \(x\) 行转移 / 不能被转移。

那么随便维护就好了。时间复杂度 \(\mathcal{O(nr + \sum S)}\)。常数略大。

P14362

玉玉了。最失败的一集中最失败的一题。

考虑新建 \(k\) 个点。\(2^k\) 枚举每个城镇,然后直接跑 kruskal,可以得到若干分。

由于只有原图 mst 上的边有用,保留这些边,这样边的量级到了 \(n\)。时间复杂度 \(\mathcal{O(2^kn\log n)}\)。还带点并查集的常数,瓶颈在于排序。可以得到 \(80\) 分。

止步于此了。实际上,每次都加边是很唐的。考虑把所有边都先加上,对于那些没开的城镇的边,不理它即可。这样就少了个 log。带点并查集的常数,可以通过。

有神秘归并做法。不会跑路了。

笑点解析:赛时拼包挂了挂成 \(24\) 分。赛后 10min 会了 \(80\)

P6000

有点红了。

首先字母串得能匹配。这个很好判。

对于某个左端点,由于字典序最小,我们肯定贪心地把它往右放。

对于区间 \([l,r]\) 容易证明当 \(l, r-1\) 的栈形态相同(或 \(l-1,r\))时,\([l,r]\) 合法。

哈希处理。那么可以 \(\log n\) 来查找每个 \(l\) 对应的 \(r\)

对于这种括号题,相似的是同样在这篇文章的 CF149D。类似地,我们每次把合法区间分割成两个合法区间。这样更好做。

P1966

排序交换。

把式子拆开,得到 \(a_i^2 + b_i^2 - 2a_ib_i\)。只需最大化 \(a_ib_i\)。排序不等式得 $a_1b_n + a_2b_{n-1} + \cdots + a_nb_1 \le a_?b_? + \cdots a?b? \le a_1b_1 + a_2b_2 + \dots a_nb_n $,其中 \(a,b\) 分别已排序。也就是反序和 \(\le\) 乱序和 \(\le\) 同序和。

于是考虑让 \(a\) 中第 \(k\) 小的和 \(b\) 中第 \(k\) 小的对应。由于我们只关心火柴高度的相对大小,离散化完可以得到两个排列。映射一下跑 LIS 即可。

P5017

补了很久前一直想写的题。

Link

P4581

黑。不过是道随机化好题。

考虑建边。假设第 \(i\) 道题由想法 \(j,k\) 组成,我们将 \(j \to i, k \to i\) 建边。那么对于每个入度不为 \(0\) 的点,我们需要求出有多少个入度为 \(0\) 的点能走到它。直接合并的话会有重复,咋做呢?

下文中称入度为 \(0\) 的点为特殊点。

上述问题是不存在确定性解法的。考虑随机化。我们给每个点随机一个权值 \(W_i\),接下来有两种做法:

Sol1:

对于每个节点,维护能走到它的特殊点的权值 \(\min\)。这个很好 \(\mathcal{O(1)}\) 维护。考虑以下这个东西:

考虑 \(n\) 个均匀随机分布变量 \(a_1,a_2,\cdots a_n \in [1, V]\)。那么 \(\min(a_1,a_2,\cdots a_n)\) 的期望大小为 \(\frac{V}{n+1}\)。也就是值域的 \(n+1\) 等分点。这个可以感性理解。

那么对于点 \(i\),维护能走到它的特殊点的权值 \(\min = w\)\(w\) 的期望大小就是 \(\frac{V}{k+1}\),其中 \(k\) 为答案。那么 \(\frac{V}{w} - 1\) 即为答案。多跑几次取平均值即可。

实际上,由于除法掉精太厉害了,考虑直接计算每组数据的 \(\sum w\)。直接用 \(\frac{TV}{\sum w}\) 即可。不会证。

Sol2:

刚才那个做法比较有病。

考虑以下这个结论:

考虑 \(n\) 个均匀随机分布变量 \(a_1,a_2,\cdots a_n \in [1, V]\)。不妨记其 \(k\) 小数为 \(a_k\)。那么有期望 \(\frac{a_k}{V} = \frac{k}{n}\)。这个很好证明。

那么有 \(n = \frac{kV}{a_k}\)。做完了。

考虑维护所有权值的区间第 \(k\) 小,这样是更精确的。合并的时候写个归并状物就好了。

P1484

好题。感觉这题很牛逼。

可以写出 \(\mathcal{O(nk)}\) 的 dp。这样没有前途,考虑反悔贪心。

考虑贪心地选择当前价值最大的树 \(a_i\)。但是可能会存在 \(a_{i-1} + a_{i+1} > a_i\) 的情况。这时候就需要反悔。具体地我们把 \(a_i \leftarrow a_{i-1} + a_{i+1} - a_i\),把 \(a_{i-1},a_{i+1}\) 删去。这样假设我们后续又选了这个 \(a_i\),相当于反悔选择 \(a_{i-1} + a_{i+1}\),此时同理处理这个 \(a_i\),后续如果再选,就相当于反悔了上次反悔操作。这个可以感性理解。

链表维护前驱即可。

P3049

又被普及组题目击杀了。

很妙的转化是将起始状态 \(A = [2, 3,5]\) 变成 \(A' = [1,1,2,2,2,3,3,3,3,3]\)。终止状态 \(B\) 同理。这样就变成了一个编辑距离状物的东西。

那么编辑距离。对于操作 \(1,2,3\) 容易转化。时间复杂度 \(\mathcal{O(n^2 \times V),V = 100}\)

P2748

考虑加强。上面的 dp 没啥前途了。考虑贪心。

注意到土块的数量极少,考虑在这上面做文章。

考虑花坛 \(l\) 的土块单位 \(i\)。假设当前缺土,两种选择:

  • 直接买。代价 \(V_i\)\(X\)
  • 从前面拿。假设从前面的 \(j\) 拿。假设 \(j\) 在第 \(k\) 个花坛。那么代价 \(V_i = |k-l| \times Z - V_j\)

\(V_i = \min(X, |k-l| \times Z - V_j)\)。多土的同理。枚举 \(k\) 可以做到 \(\mathcal{O(n^2V^2),V = 100}\)

观察式子。显然 \(l > k\)。那么 \(V_i = \min(X, lZ-kZ - V_j)\),只需求 \(\max(kZ + V_j)\),用堆维护即可。

CF1852A

性质题。

考虑二分答案。那么维护答案在序列里的排名 \(d\),倒推 \(k\) 天即可。对于第 \(i\) 天,假设当前序列中有 \(l\) 的数 \(< d\)。那么 \(d \leftarrow d - l\)。最后判断 \(d \le 0\) 即可。时间复杂度 \(\mathcal{O((k+n)\log V)}\)

发现我们做了许多重复性的操作。考虑正推。假设某天后,答案的排名为 \(d\)。假设当前序列中有 \(l\) 个数满足 \(d + i \ge a_i\),该天前的排名就是 \(d + l\)。这个跟二分中的操作本质上相同。那么做到 \(\mathcal{O(n+k)}\)

实际上,这个过程很好优化。按 \(a_i\) 来考虑。显然对于某些 \(d\),我们会在 \(a_i\) 处一直加 \(i\) 直到到达边界 \(a_{i+1}-1\)。 那么可以计算出次数 \(q = \min(k, \lfloor \frac{a_{i+1} - 1 - d}{i} \rfloor)\)。令 \(d \leftarrow d + q \times i\) 即可。当 \(d > a_n\) 时直接令 \(d \leftarrow d + k \times n\) 即可。严格线性。

ARC197C

Sol

P14525

好题。

\(\mathcal{O(n^4)}\) 的暴力是平凡的。

下文中记 \(h\) 表示矩阵行的长度,\(w\) 表示矩阵宽的长度。

考虑钦定 \(h \le w\)。枚举 \(h\) 以及行 \(i\),那么此时矩阵的长必定是由 \([i,i+h-1]\) 平移得到,换句话说,我们已经把矩阵的长给确定了。现在只需要考虑宽。由于长是确定的,对于每一列,都可以看成一个数。只需求长度 \(\ge h\) 的最大子段和即可。这个可以前缀和 + 前缀 \(\min\) 维护。

同理,钦定 \(w \le h\) 再做一遍即可。时间复杂度 \(\mathcal{O(n^3)}\)

P7840

对于一珂 \(n\) 个点的树,容易发现所有点的度数之和为 \(2n - 2\)

每个点都至少连一条边,度数至少为 \(1\)。于是我们有 \(n - 2\) 的度数可以分配。

假设对于 \(d_i\),给它分配一个度数,它的贡献会增加 \([(d_i + 1)^2 - d_i^2]v_i = v_i + 2d_iv_i = (2d_i+1)v_i\)

维护 \((2d_i + 1)v_i\) 的最小值。取出 \(n-2\) 次最小值即可。

P7809

击杀了。

第二问随便做。考虑第一问。容易发现就是找一个分界点 \(x\),使得 \(x\) 前的 \(0\) 数 + \(x\) 后的 \(1\) 数最多。前缀和 + st 维护即可。时间复杂度 \(\mathcal{O(n\log n + m)}\)。我的写法常数略大。最慢点 1.8s。

P9755

好难。暴力不会写。

考虑 A 性质咋做。此时每珂树都有一个固定的生长时间 \(t\)。有一个贪心策略是,考虑按 \(t\) 降序排序。先去种那些 \(t\) 较大的树是更优的。这个可以手玩一下证明。

那么对于当前还没种的,\(t\) 最大的树,从它祖先中深度最小的,还没种的树往下种。可以直接暴力往上跳,由于每个点只会被种一次,做到 1log。结合暴力可以获得 40pts。

考虑链。此时种树顺序是定的。只需考虑每珂树的生长时间。考虑函数 \((l,r,i)\) 表示第 \(i\) 珂树在第 \(l \sim r\) 天能生长多高。分讨即可。那么每个 \(i\) 可以二分出答案。取 \(\max\) 即可。结合上述部分分可以获得 50pts。

考虑二分答案。这样就变成了存在性问题。对于每珂树,预处理出它的最晚种树时间 \(t'\)。那么按 \(t'\) 从小到大考虑,套用 A 性质做法即可。时间复杂度 \(\mathcal{O(n\log n\log V)}\)

P14566

被击杀了哥们。

\(M\)\(A\) 中的最大值。\(M'\)\(A\) 中的次大值。\(N\)\(A\) 中的最小值。

显然我们有一个方案是令 \(p = M + 1\)。这样价值就是 \(M - N\)

然后考虑怎么做到更优。考虑令 \(p = M\),这样可以得到价值 \(M'\)

继续考虑。此时我们得到价值 \(\max(M',M-N)\)。注意到 \(a \bmod p \le p\)。所以我们不需要考虑 \(p \le M'\) 的部分。

考虑 \(p\in (M', M)\)。此时代价为 \(\max(M',M\bmod p) - \min(N, M\bmod p)\)。分讨 \(M \bmod p\) 的取值:

  • \(M \bmod p > M'\)。此时代价为 \(M \bmod p - N\),由于 \(M \bmod p < p\),即 \(M \bmod p < M\)。即原式 \(< M - N\)。不优。
  • \(M \bmod p \le M'\)。此时代价为 \(M' - \min(N, M \bmod p)\)。显然 \(< M'\)。不优。

综上,我们只需考虑 \(M - N\)\(M'\)。做完了。时间复杂度 \(\mathcal{O(n)}\)

P9118

111。

考虑 \(k \ge 3\),直接枚举到 \(V = 1 \times 10^6\) 即可。平凡。

考虑 \(k = 2\),首先显然是有 \(\sqrt{n}\) 个。但是会有重复的。你考虑某个 \(X = a^2 = p^k\)。显然有 \(2 \mid k\)。那么只需在对 \(k \ge 3\) 做暴力时,记录下 \(2 \mid k\)\(p^k\) 的数量即可。注意要先对 \(2 \mid k\) 的东西做更新。再对 \(2 \nmid k\) 的东西做更新。过了。常数挺大。

发现自己是 zz。只需在更新时直接判断这个数是不是完全平方数即可。更好想。

P5022

考虑树咋做。显然从 \(1\) 出发,每次走字典序最小的点最优。

考虑基环树咋做。断掉某条边后沿用树的做法即可。\(\mathcal{O(n^2)}\)

使用基环树相关 trick 可以做到 1log 甚至线性。不会基环树 /ll

P5937

口胡了没写。

奇偶性是具有传递性的。每次只需合并 \(l-1,r\)。使用种类并查集。\(f_i\) 表示与 \(i\) 奇偶性相同的集合。\(f_{i+n}\) 表示与 \(i\) 奇偶性不同的集合。

CF939E

大神呐。

推一下式子。首先证明最大值一定被选。

原答案 \(\displaystyle A = \frac{|S| \times \max(S) - \sum S}{|S|}\)。如果最大值没有被选,换上后答案变为

\(\displaystyle S = \frac{|S| \times max(S+ X) - \sum S - X}{|S|}\)

变化的值就是 \(\displaystyle \frac{|S| \times X - X}{|S|}\),显然为正。

那么最大值一定被选。这样只需考虑选择的数量以及选择的和。容易证明一定优先选小的。双指针维护即可。

P6189

和 noip 计划里的某道题挺像。

首先考虑根号分治。令 \(m = \sqrt{n}\),对于小于 \(m\) 的数能凑出来的和我们做完全背包。对于 \(> m\) 的数,由于累积起来很快,可以证明不超过 \(m\) 个就能凑成 \(n\)

所以考虑 \(n\sqrt{n}\) 的 dp。\(f_{i,j}\) 表示凑成 \(i\),使用了 \(j\) 个数的方案数。简单转移可以做到根号。

枚举和 \(p + q = n\),方案数相乘即可。总的时间复杂度 \(\mathcal{O(n\sqrt n)}\)

posted @ 2026-05-23 17:32  Fearlessy  阅读(5)  评论(0)    收藏  举报