2024.10月模拟赛总结

· · 生活·游记

国庆培训

10.3 训练报告

只做出 B 题。

A 题一直在想如何贪心,没注意到训练专题是 dp(但如果不告诉你是 dp 也要想得到),于是考虑 \mathcal O(n^2) dp。

f_i 表示前 i 个数中最小的极差和(合理分组后),答案即为 f_n,状态转移式为 f_i = \min\limits_{j \le {i-3}} (f_j + a_i - a_{j+1})。可以发现原式等于 f_i = \min\limits_{j \le i-3} (f_j - a_{j+1}) + a_i。由于 a_i 是一个定值,且括号里的式子只与 j 有关,所以一边枚举 i,一边用一个变量来计算 \min (f_j - a_{j+1}),加起来即为 f_i 的值。

B 题 \mathcal O(nm^2p) 的 dp 是可以过的,考虑设 dp_{i,j,k,l} 表示在第 i 行第 j 列前面,当前行已经选了 k 个数且总和 \bmod p =l 的最大和。然后不难用刷表法列出转移式,再注意一下边界的转移即可。

C 题没想到用数据结构解。考虑用一个小根堆存下想要喝水的人,再用一个队列存排队喝水的人。观察一些性质可得队列里的人的编号是单调递减的。

剩下模拟即可,要注意一些细节(比如一个正在排队的人喝到了水,离开时,就可能有人想喝水等)。

10.4 训练报告

自己做出 A,B 两题,C 题看了原题的题解学会了。

A 题第 1 小问就是最短路,第 2 小问需要在最短路的基础上统计最大值。我一开始想的 bfs,但是为了统计最大值需要重复更新,而且是在线回答询问的,会 T 掉两个点。

不妨换一种思路,注意到 n \le 300,可以使用 \text{floyd} 离线求最短路,并且能够在三重循环的过程中顺带更新最大值。这样我们就可以 \mathcal O(1) 解决询问。

B 题一开始想的对于每个点 dfs 求三元环,其复杂度可以被卡成暴力的复杂度。考虑一个重要的性质对于一组 (x,y,z),其中 yx 的邻居,zy 的邻居,zx 的邻居。换言之,z 是另外两个点共同的邻居。那么首先以 \mathcal O(n^2) 枚举 xy,满足 yx 的邻居。然后计数它们共同的邻居 z

具体实现可以在输入时用 bitset 记录邻居,最后取一下交集。但最后答案需要定序,所以要除以 3!,也就是 6

C 题发现 k 很小,考虑状压 dp。设 f(i,t) 表示前i个位置,最后 k 个数的状态为 t 时的方案数。

f(i-1,x) = 0 的方案排除,因为不会对下一步产生任何贡献。

分类讨论。若 i<k,那 t 就不可能成为长度为 k 的回文子串,直接累加方案数即可。若 i \ge k,那么只要判断一下末尾的 k 个位置是否是回文子串即可(因为其它的长度为 k 的子串的合法性是由 f(i-1,x) 的值决定的)。

后来订正出 E 题。E 题乍一看不太好做。我们不妨把人看作点。点的度数小于 k 的一定不能参加 live。然后把这类点及它们的连边删去,如果删边之后,还有度数小于 k 的点,继续执行此类操作,类似于拓扑排序。

正着做不好做,因为一个点可能影响多个步骤,提前删会波及后面的操作,每次删完后要重新建图,拓扑。复杂度为 \mathcal O(nm)

所以考虑倒着做,每删一条边,我们就将边两端的点度数分别减一,如果删完之后出现了小于 k 的点,则继续拓扑删点。时间复杂度为 \mathcal O(n+m)

10.5 训练报告

自己做出 A,B,C,D 题,E 题拿了 20 分。

订正出 F,G 题。

A 题直接二项式定理展开。答案为 C_k^{n} a^n b^m

B 题同余式先转换成等式,然后 exgcd 求解,最后转成最小整数解(往上或下调整 kb)即可。

C 题利用唯一分解定理展开,然后指数都乘上 b。此时每个质因数的贡献可以用等比数列求和公式快速计算,如果除数 \bmod 9901 的逆元不存在,那么把原式展开,发现此类贡献为 1,直接相加即可。

D 题发现 \mathcal O(nm) 的做法可以过。考虑在 [1,m] 中枚举解 x,然后用秦九韶 \mathcal O(n) 判定是否合法(不用秦九韶,累乘 x 计算也可做到 \mathcal O(n))。接着发现似乎需要高精度,但那样输入会炸,直接考虑模一个大质数。设这个质数为 p,记原多项式为 f。如果 f(x) \bmod p =0,我们就认为 f(x) = 0,碰撞的概率很小,可以过。

E 题目前只会 \mathcal O(n) 暴力。

F 题有一个很关键的性质,即关键点。关键点指的是一个排列中不是其它数倍数的数。一个排列对答案的贡献即这个排列中最后一个关键点的位置。我们先埃筛出所有关键点,记关键点的个数为 sum。接着我们枚举最后一个关键点可能出现的位置,利用组合计算答案。最终答案为:

\sum\limits_{i = sum}^{n} i \times C(i-1,sum-1) \times sum! \times (n-sum)!

G 题要求 \sum\limits_{i=0}^{\infty} C_{nk}^{ik+r} \bmod p 的值。考察 C_{nk}^{ik+r} 的组合意义。在 nk 个物品中,选出 j 个物品的方案数,其中有 j \bmod k =r。简化这个组合数,设 f_{i,j} 表示在前 i 个物品中选 s 个,且 s \bmod k = j 的方案数。于是有递推式:

f_{i,j} = f_{i-1,j}+ f_{i-1,(j-1)\bmod k}

由于 f_{i,j} 只与 i-1 层的方案数有关,所以可以用矩阵递推,套个快速幂即可求。

10.19

10+40+0+0=140。废了。

T1 二进制简单模拟题。

T2 考虑用两个栈来维护数字和符号。当符号优先级更高时(乘除),把数字栈的栈顶栈顶弹出后栈的栈顶先进行运算,压回栈中。如果遇到括号先把左括号入栈,每遇到一个右括号,不断往下压栈,途中该算的算,直到遇到左括号。在这个过程中顺便判断不合法情况,然后就做完了。

T3 考虑状态的设计,记 \max{[A,B,C]} = N,朴素设计是 O(n^3) 的,注意到每次操作后,必有一个杯子满或者空。所以可以将其中的一维改成 0/1,再把另一维记成哪一个杯子是满的/空的,即记成 0/1/2,还有一维可以用来表示第二个杯子,最后一个可以通过 a+b+c-\text{前两个杯子的水量和} 来求出。

dp_{i,0/1,0/1/2} 表示哪个杯子是满的/空的,它的下一个杯子的状态是 i,最后一个杯子的状态为 a+b+c-i- A/B/C/0。然后 bfs 一下即可(状态的优化用于 bfs 的重复状态判定上)。

第四题不会,留空。

10.24

100+25+0+0=125。废了。

T1 简单题,二进制模拟即可。

T2 赛时没想到,赛后去吃饭时立马想出来了。直接做不好做,考虑 dp,设 dp_i 表示前 i 个字符构成的字符串是否合法(能用元素周期表的字母拼起来),分三种情况讨论:

  1. 不合法。

如果合法,取任意一种合法方案,记录转移的 last(从 dp_{i-1} 还是 dp_{i-2} 转移而来)。

最后倒序跑回去即可。

T3 好题 ,不过学长的题解有点看不懂?。首先正难则反。然后容易发现每个数至多操作一次。于是贪心地考虑,我们需要选出一段答案序列的子串,确保它们一直都是不动的。也就是说,原本这个子串只是一个子序列,通过内部的数移动到两端来产生贡献。

还有一个性质,就是这段不动的子串,它们的值域在离散化后要保持连续,比如 [1,3,2] 这段子串,如果选择 [1,3],那么 2 就无法插入,所以 [1,3] 是不合法的。然后单调队列从小到大维护即可。

具体细节可以见 P3411 第一篇题解(膜拜 Ccyj 学长 orz)。

第四题不会,留空。

10.25

100+15+15+0=130。倒一,废了。

第一题,简单题,考虑贪心开桶计数。

第二题,想到 85 分做法,但写炸了。考虑 dp。设 dp_{i,j} 为第 i 行第 j 个孔洞能滚动到的最大行。然后如下图所示,容易发现,可以发现可以倒序二分转移。 注意本行掉不下去的情况。由于下一层的生成孔洞是有序的,所以还可以用双指针维护,在此膜拜 hjx 学长。

11.9 日补:

第三题会了但懒得写了,而且 hjx 学长题解写的更好,就直接放了他的题解: