MX 练石 2025 NOIP #9
继续怒砍 20pts!/oh /oh /oh
2025 --【炼石计划 NOIP】-- 第九套
时间:4.5h (2025.09.25 07:40~12:10)
题目数:4
难度:
| A | B | C | D |
|---|---|---|---|
| \(\color{#52C41A} 绿\) | \(\color{#3498DB} 蓝\) | \(\color{#9D3DCF} 紫\) | \(\color{#BFBFBF} ?\) |
| *1600 | *2100 | *2700 | *? |
估分:20 + 0 + 5 + ? = 25 + ?
得分:20 + 0 + 0 + 0 = 20
Rank:108/179
场祭
读题。
草咋这么难。
A,推了一会儿发现可以转化为对于 \(n = \prod p_i^{a_i}\),\(\forall i\) 需要满足选择的数集 \(S\) 中 \(p_i^{a_i}\) 至少出现一次,\(p_i ^0\) 至少出现一次,看上去很对,但是没有毛线用,因为 \(S\) 的什么东西都不固定,怎么都算不出来,打暴力走人。
B,想 dp 但是不会处理插入中间的情况。去想状压,想了个 \(O(2^n nx)\) 的状压,就是直接枚举 \(f_{s,i,j}\) 表示选 \(s\) 这些数,最后一个是 \(i\),长度为 \(j\) 的方案数。写写写发现是 \(O(2^n n^2 x)\) 的不过没什么区别,哦好像可以优化,因为如果不安排没必要的空格,长度最大为 \(n^2\) 左右,这样是 \(O(2^n n^4)\) 的,>1e9 了。本来想压压长度来着,然后打表发现长度最多为 \(n(n-1) + 1\),压不压没啥区别。
不过应该可以卡过去一部分,写写写,没过样例,改了几个肉眼可见的错之后还是没过,试试小数据,哦原来最后考虑空格计数的时候直接组合数会算重吗。
想想想,就是一个形如 \(\sum x_i = k\) 且规定部分 \(x_i \ge lmt_i\) 的方程,有多少解,但是不会。
那就只能在 dp 里考虑空格了,又回到了 \(O(2^n n^2 x)\),写写写,发现需要考虑在没有限制的地方加空格的情况和有限制的地方加空格的情况,最后想到什么来着忘了,总之发现这个东西很难处理,然后就没有然后了。
只能打暴力了,但是暴力也不会,跳了吧。
C 暴力,然后发现打的暴力是 \(O(n^2V)\) 的,一个 subtask 也过不了,打了菊花图的特殊性质走人。
D 暴力模拟,其它的不会。应该有一点分吧。
寄寄寄,摆烂去看番了。最近也是开始看魔圆了呢。
补题
补 A,啊?我的思路对完了啊?注意到 \(n\) 的质因子个数很少只有 \(O(\log n)\) 个然后直接暴力就可以啦?
哦只对了一半。还要容斥。考虑直接枚举每个质因数,要求出现次数区间是 \([0,a_i]\)(意思是,取值范围可以是这些,但不保证一定,因为那太困难了)且 \(0,a_i\) 都至少有一个。那么可以 \(+[0,a_i]\),再把没有 \(0\) 的和没有 \(a_i\) 的减掉,即 \(-[1,a_i]\)、\(-[0,a_i-1]\),然后发现多减了一部分,加回来即可,即 \(+[1,a_i]\)。
然后计数,对于每个区间 \([l_i,r_i]\),因为 \(S\) 是个集合不能出现重复元素,所以贡献就只能是这 \(r_i - l_i + 1\) 个元素选或不选,同时不能全都不选,则答案为 \(2^{r_i - l_i + 1} - 1\)。
考虑又加了另一个区间 \([l_j,r_j]\),因为质因数不同,这个区间也不可能与 \([l_i , r_i]\) 重复,所以答案就是 \(2^{(r_i - k_i + 1) \times (r_j - l_j + 1)} - 1\)。
于是 \(k\) 个区间的贡献就是:
注意到只与区间长度有关,所以 \(-[1,a_i]\)、\(-[0,a_i-1]\) 可以放到一起算。
因为 \(S\) 不能选 \(0\),所以爆搜过程中不能直接贡献,需要记录一下 \(2\) 的多少次幂,最后结束统计答案的时候再 \(-1\)。
复杂度是 \(O(3^k)\) 的,其中 \(k\) 是 \(n\) 的不同质因子个数。
补 B,哦还是对了一半,对了一半但是一点分没有糖丸了 /ll
先是上面那个方程解数的问题。唉感觉这种东西应该很简单呀我怎么不会呢 /yun,还是太不会数数了。直接令所有 \(x_i \gets x_i - lmt_i\),同时 \(k \gets k - \sum lmt_i\),然后就是限制全都是非负整数了直接隔板法就可以了。欸不是?我到底是怎么回事连这玩意都没想到啊 /ll,不就一步很明显的转化嘛。痛失 70pts 气气气。
然后正解。有点神仙了。显然 dp(非状压)是要加状态的,但是加什么状态呢?
……根本想不到加什么状态(
哦对了先令 \(f_{i,j}\) 为考虑前 \(i\) 个数,形成的长度为 \(j\) 的方案数。
从麻烦的地方入手。在加入 \(i+1\) 的时候,如果插入前面某两个数之间,那么虽然容易确定插入后的贡献,但是插入前的贡献是不好办的,而这一部分又不能不算,因为加上插入后的贡献之后必须要减去插入前的贡献。所以考虑固定插入前的贡献,直接在插入前判断是否有插入,且若两个数之间有插入,则直接省略掉这两个数之间的贡献。
于是令 \(f_{i,j,k}\) 为考虑前 \(i\) 个数,形成的长度为 \(j\),需要插入 \(k\) 个更大的数的方案数。转移是平凡的。
为了方便可以把每个空格段的贡献算到它较大的那个端点身上,这样加入一个数 \(x\) 产生的贡献:若不需要在它旁边加入更大的数,贡献就是 \(x\);否则贡献为 \(0\),因为空格段的长度只取决于较大的那个端点。
不过此时需要注意初始状态为 \(f_{1,0,0} = 1\) 而不是 \(f_{0,0,0} = 1\),因为只有有数才可能存在长度。
C 补不动。仍然没有视频题解。
upd:有了。
好题!
trick:直径问题考虑重心。
先考虑重心在点上的情况,令重心为 \(x\)。同时令根节点为 \(x\)。
引理 #1:
- 令对于一个点 \(u\),距离 \(u\) 最远的点到 \(u\) 的距离为 \(d(u)\)。
- 对于树上任意一个点 \(u\),满足树的直径 \(\le 2d(u)\)。
- 对于树的重心 \(x\),满足树的直径 \(= 2d(x)\)。
那么对于一次询问 \(k\),要求的问题就转化成了进行 \(k\) 次操作后,使得 \(d(x)\) 最小。
有点像二分,所以考虑反过来,求当钦定 \(d(x)\) 时,最多能进行多少次操作。
令初始情况下(边权均为 \(1\))的 \(d(x) = r\)。
考虑 \(d(x) \le r+p\) 的充要条件是什么。显然可以贪心地思考。
引理 #2:
在操作的时候,我们断言操作叶子与其父亲连的那条边一定不会更劣。
Proof. 因为 \(d(x)\) 最终一定是到叶子的距离,而操作叶子的边只会使 \(1\) 个叶子与 \(x\) 的距离 \(+1\),但操作其它边就会使 \(\ge 1\) 个叶子与 \(x\) 的距离 \(+1\)。QED.
令 \(S\) 为以 \(x\) 为根时的所有叶子组成的集合。那么分讨 \(p\) 的取值:
-
若 \(p=0\),即 \(d(x)\) 的值和初始值相等。显然对于所有 \(y \in S\),\(x \leadsto y\) 的边权和的和一定为 \(r \cdot |S|\),再减去本来就有的边权 \(\sum _{y \in S} dis(x,y)\)。即:
\[r \cdot |S| - \sum _{y \in S} dis(x,y) \] -
若 \(p > 0\),因为 \(p=0\) 已经使得所有 \(dis(x,y)\) 都相等了,所以直接给所有叶子 \(y\) 的边都 \(+p\) 即可。即:
\[{\color{#EEAADD} p \cdot |S|} + {\color{#66CCFF} r \cdot |S|} - {\color{#66CCFF} \sum _{y \in S} dis(x,y)} \]
然后注意到,上面蓝色部分是常数(与 \(p\) 无关),粉色部分与 \(p\) 成正比,所以可以把它看作答案关于 \(r + p\) 的一次函数(此处看作 \(r+p\) 的一次函数而不是 \(p\) 是为了后面方便)!
即最大操作操作次数关于直径的 \(\frac 1 2\) 的一次函数。
当然,这是对于固定 \(x\) 的情况。尝试推广,可以发现因为重心一定不是叶子,所以任何一个重心所对应的 \(|S|\) 都是相同的,也就是说直线的斜率是相同的!所以只需要考虑截距最大的直线就可以了!
然后 \(r\) 和 \(\sum _{y \in S} dis(x,y)\) 都可以通过简单的换根 dp 求得,所以我们就可以在 \(O(n)\) 的时间复杂度求出来每一条直线了。
但是其实并非直线,因为对于每个 \(x\),都规定了 \(\left( r , r \cdot |S| - \sum _{y \in S} dis(x,y) \right)\) 是一次函数的起始位置,也就是说横坐标最小为 \(r\)。
所以可以考虑按照 \(x\) 对应的 \(r\) 大小,从左往右依次加入每条直线,并维护直线截距(注意是与纵坐标轴的截距,而不是上面的式子)的最大值。
……好像跑的有点太远了,回到问题,对于一个 \(k\),考虑如何回答询问。
比较容易的,考虑在上面加直线的过程中,令 \(f_i\) 为直径为 \(i\) 时的最大操作次数,因为 \(r\) 一定不会超过 \(n\),所以 \(f_i\) 只需要维护到 \(i \le n\) 即可,然后二分 \(\ge k\) 的第一个 \(f_i\),这个 \(i\) 即为答案,若 \(k > f_n\) 直接根据斜率算即可。注意需要乘 \(2\)。
做完了。
哦还要考虑重心在边上的情况。可以发现重心在边上的时候,在这条边的中点处一定是最优的,所以就和重心在点上的情况同理了。
天依宝宝可爱!

浙公网安备 33010602011771号