2026春好题记录

P3971 [TJOI2014] Alice and Bob 5.9

我大抵是睡着了。

tag:Ad-hoc,贪心,图论建模

题意:有一个未知序列 \(\{x_1,x_2,\dots,x_n\}\),已知以每个 \(i\) 为结尾的最长上升子序列的长度,求以 \(i\) 开头的最长下降子序列的长度之和的最大值。

先考察原数列有没有值相等的情况,发现你可以将前一个调大,后一个调小,这样肯定不劣。于是原数列一定得是一个排列。

再考察数列的最长上升子序列,发现若存在 \(i<j\)\(a_i=a_j\),那么 \(x_i>x_j\)。而对于 \(x_i\),以它为结尾的最长上升子序列长度 \(a_i\) 一定是从 \([1,i)\) 中的一个 \(a_i-1\) 转移过来的。

那么根据上述性质,\(x_i\) 一定比最后一个 \(x_j=a_i-1\)\(x_j\) 要大。而且如果 \(x_i\) 更大的话 \(b\) 会更小,所以你考虑图论建模,对于每个 \(i\) 找到 \(j\)\(j\rightarrow i\) 连一条边,表示偏序关系。然后对于同一层的点,靠后的需要更小,于是你按输入顺序的倒序连边,跑 \(\text{dfs}\),每个点的 \(\text{dfn}\) 即为 \(x_i\)

再跑一边最长下降子序列即可。

[ARC107D] Number of Multisets 5.2

虽然不难,但很有意思的题。

加深此类 trick 的印象。

tag:dp

题意:求可重集 \(S\) 的个数,满足 \(|S|=n\)\(\sum\limits_{k\in S}k=m\)\(\forall k\in S,\exists t\in \mathbb{N},k=2^{-t}\)

相当于你可以对 \(n\)\(1\) 做若干次前缀 \(\times \frac{1}{2}\) 操作使 \(\sum\limits_{k\in S}k=m\)

\(dp_{i,j}\) 表示让前 \(i\) 个数之和为 \(j\) 的方案数,转移有:

  • 所有数 \(\times \frac{1}{2}\),则 \(dp_{i,j}\leftarrow dp_{i,j\times 2}\)
  • 加入一个 \(1\),则 \(dp_{i,j}\leftarrow dp_{i-1,j-1}\)

这样就在 \(O(n^2)\) 内解决了这个问题。

P8688 [蓝桥杯 2019 省 A] 组合数问题 题解 6.0

tag:Lucas 定理、数位 dp

题意:给定 \(n,m,p\),求 \((i,j)\) 的对数满足 \(1 \le i \le n,0 \le j \le \min(i,m)\)\({i\choose j} \equiv 0\pmod{p}\)\(p\) 是质数。

观察到这个条件是一个组合数对一个质数取模后的东西,可以联想到 Lucas 定理。则

\[{i\choose j}\equiv \prod_{k}{i_k\choose j_k}\equiv0\pmod{p} \]

其中 \(i_k,j_k\) 分别是 \(i,j\)\(p\) 进制意义下的第 \(k\) 位。那么要想让这么多个数乘起来是 \(p\) 的倍数,则其中必有一个数是 \(p\) 的倍数。即存在 \(k,{i_k\choose j_k}\equiv 0\pmod{p}\),等价于 \(i_k<j_k\)

存在这件事难以刻画,我们考虑容斥,现在需要求 \((i,j)\) 的对数,其中 \(i,j\)\(p\) 进制下的每一位 \(i_k,j_k\) 都满足 \({i_k\choose j_k}\not\equiv 0\pmod{p}\)\(i_k\ge j_k\)

那么就可以开始数位 dp 了,设 \(f_{i,0/1,0/1}\) 表示从高到低考虑到前 \(i\) 位,\(i\) 有没有顶到头,\(j\) 有没有顶到头。转移进行分讨即可。

时间复杂度 \(O(T\log_{k}n)\)

[AGC054C] Roughly Sorted 5.2

tag:计数

题意:有一个排列 \(P\),可以交换 \(P\) 的相邻两项,使其每个 \(i\) 的逆序对数不超过 \(k\)。你得到了经过最小次数操作后的排列 \(P'\),求有多少种可能的原始排列 \(P\)

该加训此类题型了。

考虑刻画逆序对个数这件事,你发现如果 \(P\) 的逆序对个数不超过 \(k\),那么 \(1\) 的位置肯定不能超过 \(k+1\)。同理 \(i\) 的位置肯定也不能超过 \(k+i\)。那么你就有 \(P'_i\le k+i\)

如果 \(P'_i<k+i\),因为你要最小化操作次数,所以在原排列中这个 \(i\) 的位置本来就会在这里,要不然你也不会去把他往左边移动。

所以我们只需要考虑 \(P'_i=k+i\) 的贡献,它一共会有 \(n-k-i-1\) 种取值。

[ARC139D] Priority Queue 2 6.2

tag:求和转 01、计数

题意:给你一个数列 \(a_i\in [1,m]\),你要进行 \(k\) 次操作,每次操作形如:选择一个 \([1,m]\) 中的整数,加入 \(a\),然后删去 \(a\) 中第 \(x\) 小的元素。求所有方案操作后 \(a\) 的和之和。

考虑把求和形式改为 01 序列形式,有 \(\sum\limits_i a_i=\sum\limits_j\sum\limits_i[a_i\ge j]\)。于是考虑枚举 \(j\),计算 \(\sum\limits_i[a_i\ge j]\) 的总和。

设初始时满足 \(a_i\ge j\)\(i\) 的个数为 \(c\),现在一次操作即为:

  • \(c\) 每次有 \(m-j+1\) 种可能 \(+1\),若 \(c\ge n-x+1\)\(c\gets c-1\)

枚举 \(c\) 被增加的次数 \(l\),则这种变化的可能情况有 \(\binom{k}{l}(m-j+1)^l(j-1)^{k-l}\) 种,而最终 \(a_i\ge j\) 的个数也同样可以计算:

  • \(c\ge n-x+1\),则最终 \(a_i\ge j\) 的个数为 \(\max(n-x+1,c+l-k)\)
  • \(c<n-x+1\),则最终 \(a_i\ge j\) 的个数为 \(\min(n-x+1,c+l)\)

直接统计即可。时间复杂度 \(O(mk)\)

#8692. Yet Another Convolution 6.0

tag:(整体)二分、莫反

题意:给你两个数列 \(a,b\),求 \(c_k=\max\limits_{(i,j)=k}|a_i-b_j|\)

如果可以快速计算 \(c_1\),计算它的时间复杂度是 \(T(n)\),那么 \(c_i\) 都可以在 \(T(\frac{n}{i})\) 的时间复杂度内解决。

不妨设 \(a_i\le b_j\),我们现在需要找到最小的 \(b_j\) 满足 \(i\perp j\)。考虑整体二分,转化为存在性问题,只需要判断是否存在 \(b_j\le x\)\(i\perp j\)。有 \(\sum\limits_{j=1}^{n}[b_j\le x][i\perp j]=\sum\limits_{d\mid i}\mu(d)\sum_{d\mid j}[b_j\le x]\),第二个 \(\sum\) 容易优化,时间复杂度可以做到 \(O(\sum d(i))=O(n\log n)\),那么 \(T(n)=O(n\log^2n)\),总时间复杂度为 \(O(n\log^3n)\)

/se 6.0

tag:分析性质、dp

题意:将 \(n\) 条线段划分为不超过 \(k\) 个集合,求每个集合中所有线段的交的长度之和的最大值。

对于两个线段 \(j\subseteq i\),如果 \(i\)\(j\) 被分到一组,那么 \(j\) 不会造成任何影响。为了让总长度最大,我们要么把被包含线段 \(j\) 单独放进一个集合,要么就把它随便扔进一个包含它的集合里。

当我们把这些线段删去之后,剩下的线段有一个很好的性质:如果将这些线段按左端点从小到大排序,那么它们的右端点也一定是严格单调递增的。

考虑 dp,设 \(dp_{i,j}\) 表示前 \(i\) 条前段划分成了 \(j\) 个集合的答案。最后 \(dp_{n,j}\) 和被删去的线段合并即可。时间复杂度 \(O(nk)\)

叁仟肆佰万 5.5

tag:计数、dp

题意:求分割一个序列使得每段 \(\operatorname{mex}\) 值相等的方案数。

你发现如果一段区间有 \(0\),那么其他区间也必须有 \(0\)。以此类推,可以得到每段区间的 \(\operatorname{mex}\) 就是序列的 \(\operatorname{mex}\)

然后对于一个右端点 \(r\),合法的 \(l\) 应该是一段前缀,所以你双指针维护即可。时间复杂度 \(O(n)\)

P4099 [HEOI2013] SAO 6.5

tag:计数、dp

题意:给你一棵有向树,求其拓扑序个数。

\(f_{u,i}\) 表示以 \(u\) 为根的子树内 \(u\) 的拓扑序在第 \(i\) 个的拓扑序的个数。

考虑对于 \(u\) 枚举它的儿子 \(v\),对这条边的方向进行讨论:

  • \(u\rightarrow v\)。考虑如何从 \(f_{u,k}\) 转移至 \(f_{u,i}\)。最终的拓扑序形如 \(\dots u\dots v\dots\),那么你就需要将 \(u\) 的拓扑序列和 \(v\) 的拓扑序列拼起来,其中需要从 \(v\) 的前几个数里边拿几个塞到 \(u\) 前面,使得它从第 \(k\) 位变成第 \(i\) 位,容易得到转移

\[f_{u,i}=\sum_{k\le i\le j+k-1}f_{v,j}f_{u,k}\binom{i-1}{k-1}\binom{sz_u+sz_v-i-1}{sz_u-k} \]

  • \(v\rightarrow u\),最终的拓扑序形如 \(\dots v\dots u\dots\),后续步骤和上述情况相似。

然后可以使用前缀和优化。时间复杂度 \(O(n^2)\)

CF1146H Satanic Panic 6.2

tag:计算几何、dp

题意:求平面 \(5\) 个点的凸包数量。

考虑凸包有一个性质,它上面的边斜率按一定顺序单调递增,那你就可以开始 dp 了。

先把 \(n^2\) 条边搞出来排个序。考虑 dp,设 \(f_{i,j,k}\) 表示从 \(i\) 走了 \(k\) 步到达 \(j\) 的方案数。

然后按边的顺序更新,对于 \((u,v)\),转移有 \(f_{i,v,j}\leftarrow f_{i,v,j}+f_{i,u,j-1}\)

时间复杂度 \(O(n^3k)\)\(k\) 在此处为 \(5\)

P14637 [NOIP2025] 树的价值 7.5

tag:发现性质、dp

题意:给你一棵树,给每个点设点权,使 \(\sum \operatorname{mex}(S_u)\) 最大,其中 \(S_u\) 表示 \(u\) 的子树点权集合。

好题啊。

你先考虑整棵树的结构:对于每个点,它肯定是先从某个儿子的 \(\operatorname{mex}\) 转移过来,然后使用若干还没被使用的点(称为自由点)得到的。

那么现在就有一个 \(O(n^3)\) 的 dp 了:\(dp_{u,i,j}\) 表示 \(u\) 子树 \(\operatorname{mex}\)\(i\),还有 \(j\) 个自由点,得到的子树最大价值和。有 \(48\) 分。

这个状态不能接受。但是这道题给出了深度的性质:\(m\le 800\)。这启发我们考虑设深度有关的状态。

想到链剖分。考虑将转移过来的那个点记为重点,其余点记为轻点,那么现在这棵树就变成了一个剖分结构。

考虑拆贡献,容易发现对于一个点,当它对答案产生贡献时,它肯定从一个自由点变成了不自由点。这个贡献会从它产生贡献开始,一直往上爬重链,直到它被弃用,即到达这个重链的顶部。

因此每个点产生的最大贡献为其上重链链长的最大值。

那么现在就有一个 \(O(nm^2)\) 的 dp 了:\(dp_{u,i,j}\) 表示 \(u\) 到根节点的重链最长为 \(i\),它现在所在链长为 \(j\),得到的子树最大价值和。转移是简单的。有 \(76\) 分。

这个状态还是不能接受。观察上面所述的状态,这个 \(j\) 的定义其实非常浪费。

分析性质,对于一个点 \(u\),实际上只有如下几种情况:

  • \(u\) 子树内所有重链都不如 \(u\) 祖先的最长重链长,可以将 \(u\) 子树内所有重链删掉,增加价值;
  • \(u\) 所在的重链是最长的 \(u\) 最先的最长重链,那么你不需要改动;
  • \(u\) 所在的重链较短,而子树内有一条重链较长,可以将所有较短的重链删掉,将那条重链一直传递到 \(u\),从而变为以上两种情况。

那么可以设计出这样的状态:\(f_{u,i}\) 表示点 \(u\) 的贡献为 \(i\),并且 \(k=1\)\(g_{u,i}\) 表示点 \(u\) 的贡献为 \(i\),并且 \(k=i\)

考虑转移。\(g\) 的转移是简单的:

\[g_{u,i}\leftarrow\max_{v\in son_u}\{i+g_{v,i+1}+\sum_{v'\in son_u,v'\not=v}f_{v',i}\} \]

可以 \(O(nm)\) 做。

考虑 \(f\) 的转移。首先若 \(u\) 子树内全是轻点,那么 \(f_{u,i}\leftarrow i\times sz_u\)

否则 \(u\) 的子树内存在一个重点 \(v\)。那么这个新的链就需要产生作用,也就是说对于 \(f_{u,i}\),链长需要不少于 \(i\)。而且对于 \(u\)\(v\) 链上的点 \(w\),它们的儿子也会是轻点,否则将他们改成轻点对答案的贡献一定会更多。那么设 \(u\)\(v\) 距离为 \(i\),有转移

\[f_{u,i}\leftarrow i(i-1)+g_{v,i}+\sum_{\substack{x\in son_w\\ w\in\operatorname{path}(u,v)}}f_{x,i} \]

用你喜欢的数据结构进行维护即可。遍历子树内每个点的时间复杂度是 \(O(\sum sz_u)=O(nm)\) 的,这部分的时间复杂度即为 \(O(nm\log n)\)

P14638 [NOIP2025] 序列询问 7.0

tag:数据结构

题意:给你 \(q\) 个询问,每个询问有一个区间 \([L_i,R_i]\),每次询问,对每个 \(i\in[1,n]\),你需要求出 \(\max\limits_{1\le l\le i\le r\le n}\{\sum\limits_{i=l}^{r}a_i \mid L_j\le r-l+1\le R_j\}\)

考虑直接拍一个裸的滑动窗口,这就有 \(45\) 分了。那这题应该跟滑动窗口有很大关系。

考虑性质 D,区间一定过中点。那么你考虑将区间分成两半,区间和的 max 就相当于左半边区间和的 max 加上右半边区间和的 max。求出前后缀的 max,当你固定右端点时,合法的左端点就是一段区间,直接做滑动窗口即可。

考虑性质 E,将序列分成四块即可。那你应该就能联想到正解了:考虑倍增分块,分出 \(O(\log n)\) 个块后进行统计即可。

P6891 [JOISC 2020] ビルの飾り付け 4 5.5

tag:dp、交换两维

题意:给定两个长度为 \(2n\) 的序列 \(A,B\),构造一个长度为 \(2n\) 的序列 \(C\) 满足:\(C_i\in \{A_i,B_i\}\)\(|\{i\mid C_i=A_i\}|=|\{i\mid C_i=B_i\}|\)\(C_i\ge C_{i-1}\)

先考虑一个很显然的 dp:设 \(f_{i,j,0/1}\) 表示前 \(i\) 位填了 \(j\) 个 A,第 \(i\) 位填了 A/B,可不可行。时间复杂度 \(O(n^2)\),不能通过。

考虑猜测如果 \(i,0/1\) 固定,那么合法的 \(j\) 形成了一段区间。这是因为 \(A_i\)\(B_i\) 中较大数能转移的状态一定包含了较小的数能转移到的状态。那么直接 \(O(n)\) 维护即可。

P9870 [NOIP2023] 双序列拓展 6.5

tag:ad-hoc

你考虑这个拓展实际上是在搞什么事。

将其放到一个棋盘上,这相当于:设 \(A_{i,j}=[x_i<y_j]\),你现在从 \((1,1)\) 开始,每次可以向右、下、右下的 \(A_{i,j}=1\) 走,问能否走到 \((n,m)\)

先考虑特殊性质。首先如果存在 \(x_n>y_i\),那么 \(A\) 的其中一行就都是 \(0\) 了,无解;同理若存在 \(y_n<x_i\) 也无解。那么现在棋盘的第 \(n\) 行和第 \(m\) 列就都会为 \(1\) 了。

着其实给了我们相当大的启发。再考虑找出前 \(n-1\) 行的最小值 \(x_k\)

  • 若对于任意 \(i\)\(x_k<y_i\),那么第 \(k\) 行的 \(A\) 就会均为 \(1\),可以缩减问题规模;
  • 若存在 \(i\)\(x_k>y_i\),那么第 \(i\) 列的 \(A\) 就会全为 \(0\)

还可以对前 \(m-1\) 行的最大值进行相似的讨论。那么你发现你不能缩减问题规模的时候,存在一行的 \(A\) 全为 \(0\),存在一列的 \(A\) 也全为 \(0\)。那么此时你就不能到达 \((n,m)\) 了。

那么直接递归处理即可,时间复杂度 \(O(q(n+m))\)

再考虑正解,这其实没什么区别了。找出 \(x\) 的最小值 \(x_i\),找出 \(y\) 的最大值 \(y_j\)。那么第 \(i\) 行、第 \(j\) 列都为 \(1\)。把棋盘按照这两条线劈四半,就转化为了特殊性质的形式。

posted @ 2026-03-16 10:40  jeffreyli2025  阅读(5)  评论(0)    收藏  举报