2025 牛客寒假算法基础集训营 1 个人题解
这场一道 DP 都没有,思维题为主,很神奇。
A 茕茕孑立之影
显然最小的大于 $10^9$ 的质数 $1000000007$ 一定是一个合法解,仅在存在 $a_i=1$ 时无解。
如果读到 1 不要直接输出 -1,要先把数据读完。作者被这个坑了 10 分钟。
B 一气贯通之刃
图是链,答案是链的头尾,否则无解。
D 双生双宿之决
按题意用 map 计数即可,size != 2 都不符合题意,也要输出 -1。
G 井然有序之衡
先求和 $a$,如果 $sum \not= {n(n+1) \over2}$,那么无法得到目标排列,否则答案是
$$
\sum_{i=1}^{n}|a_i-i|
$$
H 井然有序之窗
蒟蒻作者麻烦的写法
作者的做法比较麻烦。考虑优先让可以选的数少的位置选。选择时先选择前面没选到的,被需要次数少的数(就是被前面给定的区间包含的次数)。使用线段树来选择。
1 |
|
标程
作者说这是一道非常典的题。
对于每个 $j$,选择填入在满足 $l_i\le j \le r_i$ 的所有 $i$ 中 $r_i$ 最小的 $i$。使用优先队列维护。
如果在选择的时候发现 $j$ 已经超出某组队列中的 $(l_i,r_i)$ ,那么无解(意味着 $a_i$ 没有数可以填入了)。没得选同样无解。
priority_queue 默认大顶堆。ranges::sort 是 C++20 引入的(牛客居然支持那么新的标准)。
1 |
|
J 硝基甲苯之袭
预处理每个数除 1 以外的约数。然后枚举每个 $a_i$ 的约数 $x$,如果 $\gcd(a_i,a_i\oplus x)=x$,那么 $a_i \oplus x$ 显然就是一个合法的 $a_j$。$a_i$ 范围很小,使用 cnt 记录数据出现次数即可。
特别的,对于 $a_i \oplus a_j=\gcd(a_i,a_j)=1$,显然只有 $a_i = a_j +1$ 时才会出现。
1 |
|
M 数值膨胀之美
从最小的数开始 *2,直到所有数都被 *2。每次将区间扩展到当前最小数的位置。时间复杂度 $O(n\log n)$。
1 |
|
E 双生双宿之错
这道题三分可以做,但作者的三分一直 80 分,不知道什么原因,非常可惜。
结论是,如果我们想要让整个数组变成同一个数的,同时代价最小,选中位数就行。
变成两个数时,排序,前后分别取中位数即可。代价是
$$
\sum_{i=1}^{n}|a_i-a_{mid}|
$$
两部分代价相加就是所求答案。
绝对值可以用前缀和 + 二分优化,比如你要求 $\sum_{i=l}^{r}|a_i-x|$,你可以
1 | auto calc=[&](ll l,ll r,ll x)->ll{ |
这样时间复杂度就是 $O(\log n)$,但我看标程就是暴力直接求了,我也懒得重新写了。
哭死,我的版本反而只有 80 分。
1 |
|
C 兢兢业业之移
其实是暴力模拟题,但作者的暴力思路有问题,没过。
暴力思路就是先把所有 1 往上推,再往左推,这样 1 聚集在左上角呈类似三角形。再把超出范围的 1 推到范围内。
怎么把 1 推到范围内?不难发现,最外面的 1 一定是上、左、下不能走(边缘和 1 视为不能走,11 交换没用),或者上、左不能走。那么当这个 1 的坐标在目标范围且满足上左不能走的条件的时候,我们判断走到目标位置了就行。显然,最初 $y > {n\over 2}$ 的 1 只需要往右、上走,$x > {n\over 2}$ 的 1 则往左、下走。不可能存在同时满足这两个条件的 1。
