牛客练习赛 137 A-G

明面上的内测唯一 AK 验题人

题目意料之中的难了,但是有点出乎意料过难了。

原本没有这个 B,出题人原本打算弱化现在的 C 放过 nm 加一个只输出删去边集大小的版本做 C(这个好像也是我的建议),在我建议下增加了输出方案做 B,然后现在的 C 不做弱化。

B 倒是合适了。

但是 CDEFG 好像还是难了,

个人评价:

整场来看是偏典的题,没有比较思维的题,相对最思维的可能就是 D 了,整体码量较高,实现难度略大。

  • A 抽象题,不做评价。

  • B 后加的题,感觉是周赛 D 这个位置题。

  • C“自认为”严格不弱于周赛 71 round F(然后这题 clist 参考是 牛客 2100)单独看,放 C 难了。(但是和后面的题整体来看还是合适的)

  • D,E,F “自认为”难度极差不超过 200,不好评价哪个容易,可能会出现,选手擅长哪个就会先过哪个。

  • G,字符串科技题,考察了字符串相关算法的应用。

A:

题意简化:

输出 的全排列题目编号。

解法一:

枚举全排列,用 A,B,C,D 替换 1,2,3,4 即可。

解法二:

事实上题目限制 ,而样例给出了 的解,所以特判 ,其它复制样例即可。

B:

题意简化:

给定一棵树,删除最少的边使得给定的 个点互不连通。

解法:

观察样例,如果注意力强可以得到 的结论。

实际上也很好理解, 个点互不连通,至少 个连通块,而反过来 个连通块形成一棵树最少加 条边。

方案构造也很容易,选择 个点中任一点做“根”,删除其它点和父节点的连边即可。

C.

题意简化:

每次 概率 ,求进行 后的序列的期望和。

解法:

首先。求和的期望是可加的,所以独立计算每一个 ,且容易发现 的结果只和不高于 二进制最高位的二进制位有关。

所以 进行 次的期望等价于 的期望,这样的值只有 个。

所以预处理每个初值进行 次的贡献。

答案即为 ,其中 是初始值。

预处理组合数, 询问组合数,时间复杂度:

D.

题意简化:

给定一个排列,求前缀 和后缀 和给定序列相同的,字典序比给定序列大的字典序最小排列。

解法:

,则 同理。

所以可以先根据前后缀 确定若干个位置的数。

的位置范围是 同理。

所以可以得到剩下数的位置范围区间。

同时,容易发现,数值大的数的位置范围包含数值更小的数的位置范围。

因为 是递增的。

所以只要最终排列每个数满足其范围区间,即是合法排列。

那么考虑字典序比原排列大的最小排列。

这大概是一个很典的贪心问题。

从后向前,尝试将当前位变大,第一个可以变大的位一定最优。

考虑有解条件:

设当前位可以移动的范围区间是 ,当前位是

那么,,且 中,存在比 大的元素即有解,这一步可以使用任意区间最值数据结构维护。

因为大数位置范围包含小数位置范围,所以一定可以交换。

最后,考虑后面的数的位置安排。

此时,问题转换成了给定若干个数的区间,求一种填法,使得字典序最小。

使用 set 维护,贪心填当前位置能填的最小数即可。

对于当前位置 ,因为区间随数增大扩大,所以在 setlower_bound 最小的 的元素即可。

时间复杂度:

E.

题意简化:

同 B,

解法:

,容易发现, 次操作过程中, 的值,至少关于 成循环节(根据鸽巢原理容易证明)。

所以 最长以 为循环节。

预处理一个循环节的贡献,令 ,那么

表示循环前的余项,那么最后计算答案时的式子为

其中, 只有 个,对于每组不同的 需要处理 ,每次预处理暴力计算是 的。

事实上,由于每一个循环节内部的数,其循环节是相同的,所以长为 的循环节只需要处理一次,而一次处理了 个数的循环节。

所以时间复杂度是均摊: 的,但是似乎循环节长度会满足一定是 的整数幂(暂时不会证明)所以时间复杂度是 的。

总时间复杂度:

F:

题意简化;

给定一个序列,求

解法:

放入 的集合中考虑,那么问题等价于在每个 中找

更进一步的,如果能快速找到 ,那么,可以将 去掉,然后再找一次,此时容易分讨:

  • 如果找到了 ,那么问题解决。
  • 反之,如果有解,那么一定是 ,此时,用 暴力去找另外两个数即可。

至此,核心问题是如何找到

,那么 就存在 ,此时暴力去找即可。

考虑莫比乌斯反演,

枚举 因子,预处理 贡献即可。

通过枚举倍数,可以做到均摊 处理因子。

因为题目保证了 互不相同,所以时间复杂度是均摊的。

综上:枚举 的因子后再枚举 的因子,时间复杂度为:,其中 表示 的因子数。本地实测仅有

若通过科技,可以做到预处理后 询问 范围内的 ,则时间复杂度仅为上式。若朴素求解 ,时间复杂度:

空间复杂度:

G.

题意简化:

给定一个字符串,求 ,最小的 满足翻转 后,

解法:

的答案可以通过 的答案扩展一个 得到。

原问题是对于 求最小的 ,从 开始和 逆序匹配,且向后第一个不匹配的字符满足

等价于,对于 ,求在反串上满足 的最大

对反串建 SAM 容易发现,合法的匹配一定是最长的 在 SAM Slink 树上对应的节点及其到根上的若干节点。而对应的 就是节点的 endpos。

而在这些节点中,容易发现,只有最长的 对应的节点,其 是可能在节点表示字符串集合之内的,其祖先节点,若要匹配 ,那一定是小于这段路径上其儿子节点在其末尾多的的第一个字符。

那么这些信息就可以在建出 SAM 后通过 dfs Slink 树预处理。

具体而言,令 表示 节点在其表示的最长字符串前加一个字符 ch 时的最大 endpos,因为子节点不唯一,但是父节点唯一,所以把预处理信息挂在子节点上, 的预处理信息即为其父节点加一个 的首字母字符的最大 endpos。

对于从 的节点更新到 的节点,笔者只会分讨,暂时好像不知道如何归一化。

具体而言,初始从根开始跳,若当前节点没有 的后继状态,则不断跳 Slink 树父节点,直到存在大于跳上来的子节点 首字母字符的 endpos(这个其实可以预处理标记,但是实际上不标记也无所谓)且存在 后继状态。

此时,根据笔者的写法和理解,需要分讨:

  • ,其中 表示 存在的最长 是当前节点表示的最长字符串长度。
    • 若后继节点 ,说明 节点需要让其 前一个字符小于 ,根据预处理信息即可获取此节点上合法的最大 endpos。若其 endpos 对于 来说是合法(即对应子串确实在 左侧,且没有越过 ),那么就跳过去,否则继续跳 Slink 树父节点。
    • 若后继节点 ,说明其前一个字符是确定的,根据 endpos 获取之,和 比较,若合法,那么就跳过去,否则继续跳 Slink 树父节点。
  • ,那么只需要考虑 endpos 是否合法即可,合法就跳过去,否则继续跳 Slink 树父节点。

对于朴素的 的情况,用一个数组存储所有字符第一次出现的位置即可判断。

时空复杂度:,其中 表示字符集大小。

全部评论
哎,题解跳度有点大,能不能给个代码呢
点赞 回复 分享
发布于 2025-04-20 15:59 北京

相关推荐

上周组里招人,我面了六个候选人,回来跟同事吃饭的时候聊起一个让我挺感慨的现象。前三个候选人,算法题写得都不错。第一道二分查找,五分钟之内给出解法,边界条件也处理得干净。第二道动态规划,状态转移方程写对了,空间复杂度也优化了一版。我翻他们的简历,力扣刷题量都在300以上。后三个呢,就有点参差不齐了。有的边界条件没处理好,有的直接说这道题没刷过能不能换个思路讲讲。其中有一个女生,我印象特别深——她拿到题之后没有马上写,而是先问我:“面试官,我能先跟你确认一下我对题目的理解吗?”然后她把自己的思路讲了一遍,虽然最后代码写得不是最优解,但整个沟通过程非常顺畅。这个女生的代码不是最优的,但当我问她“如果这里是线上环境,你会怎么设计’的时候,她给我讲了一套完整的方案——异常怎么处理、日志怎么打、怎么平滑发布。她对这是之前在实习的时候踩过的坑。”我在想LeetCode到底在筛选什么?我自己的经历可能有点代表性。我当年校招的时候,也是刷了三百多道题才敢去面试。那时候大家都刷,你不刷就过不了笔试关。后来工作了,前三年基本没再打开过力扣。真正干活的时候,没人让你写反转链表,也没人让你手撕红黑树。更多的是:这个接口为什么慢了、那个服务为什么OOM了、线上数据对不上了得排查一下。所以后来我当面试官,慢慢调整了自己的评判标准。算法题我还会出,但目的变了。我出算法题,不是想看你能不能背出最优解。而是想看你拿到一个陌生问题的时候,是怎么思考的。你会先理清题意吗?你会主动问边界条件吗?你想不出来的时候会怎么办?你写出来的代码,变量命名乱不乱、结构清不清楚?这些才是工作中真正用得到的能力。LeetCode是一个工具,不是目的。它帮你熟悉数据结构和常见算法思路,这没问题。但如果你刷了三百道题,却说不清楚自己的项目解决了什么问题、遇到了什么困难、你是怎么解决的,那这三百道题可能真的白刷了。所以还要不要刷LeetCode?要刷,但别只刷题。刷题的时候,多问自己几个为什么:为什么用这个数据结构?为什么这个解法比那个好?如果换个条件,解法还成立吗?把刷题当成锻炼思维的方式,而不是背答案的任务。毕竟面试官想看到的,从来不是一台背题机器,而是一个能解决问题的人。
牛客51274894...:意思是光刷力扣还不够卷
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务