1 条题解
-
0
C. 更新查询 – 详细题解
问题重述
给定初始字符串 (长度 ),一个索引数组 (长度 )和一个字符数组 (长度 )。每次操作选择 中的一个位置 和 中的一个字符 ,将 更新为 。所有操作按某种顺序依次执行。我们可以任意重排 和 的顺序(即重新排列操作顺序和分配字符)。求经过 次操作后能得到的最小字典序的 。
核心观察
- 一个位置可能被多次更新。最终该位置的值由最后一次(即该位置上的最后一次操作)的字符决定。之前的更新会被覆盖,因此不影响结果。
- 对于每个位置 (),记 为 中 出现的次数。若 ,则该位置永远不会被修改,最终字符就是 本身。
- 若 ,则我们将会对该位置执行 次操作,其中最后一次操作决定最终字符。前 次操作可以任意使用 中的字符(它们会被覆盖,不影响结果),但会消耗掉 中的某些字母。
- 目标:使最终的字符串 字典序最小。字典序的比较是从左到右逐字符进行的,因此我们应优先让靠前的位置尽可能小。
贪心策略
从左到右依次处理每个位置 :
- 如果 ,则 不变。
- 如果 :
- 我们需要为这个位置选择一个最终字符。为了字典序最小,我们应从 中剩余的所有字母里选择最小的那个作为该位置的最终值。
- 选择后,将该字母从 的计数中移除(表示已用于最后一次操作)。
- 该位置还需要 个额外的操作(它们会被覆盖)。这些操作可以使用 中任意剩余的字母,因为无论用什么都对最终结果没有影响。为了不浪费小字母(后面可能还需要),我们应该用最大的字母来填充这些额外的操作。具体做法是:从 向下遍历,尽可能多地取大字母,直到凑够 个。
- 处理完所有位置后, 中可能还有剩余字母,但所有操作已经用完?注意 等于所有 之和,因此 中的字母总数正好等于 ,所以最后计数会归零。
正确性说明
- 字典序最小:由于我们是从左到右处理,每个位置都使用了当前可用的最小字母作为最终值,保证了前面位置尽可能小。同时,我们用大字母填充多余的操作,保留了小字母给后面的位置,从而不会破坏后续的字典序优势。
- 可行性:因为总操作数等于 中字母总数,且每个位置 时我们分配了 个最终字母和 个填充字母,总共 个。整个过程消耗完所有字母,因此是可行的。
算法步骤
- 统计 中每个位置的出现次数 ()。
- 统计 中每个字母的频率 。
- 新建一个空字符串 。
- 对于 到 :
- 如果 :将 追加到 。
- 否则:
- 找到最小的字母 (从
'a'到'z')使得 ,将 追加到 ,并将 减 。 - 还需要 个字母来填充。从 向下到 ,每次尽量取最多,直到取够 个。(实际上,我们不需要显式记录这些填充操作,只需将 中的对应字母减少即可,因为填充字母不参与最终结果。)
- 找到最小的字母 (从
- 输出 。
复杂度
- 统计频率:。
- 处理每个位置:对于每个 的位置,寻找最小字母需要 ,填充大字母也需要 。由于 和 的总和不超过 ,总复杂度 ,完全可以接受。
示例验证
以样例2为例:,,,。
统计 :位置1出现2次,位置2出现1次,位置3出现0次,位置4出现1次。
字母频率:z:2, c:1, w:1。
从左到右:- ():取最小字母
c→ ans="c",cnt[c]=0。还需1个填充,取最大字母z,cnt[z]=1。 - ():取最小字母
w→ ans="cw",cnt[w]=0。 - ():原字符
o→ ans="cwo"。 - ():取最小字母
z→ ans="cw o z" = "cwoz"。结果与输出一致。
总结
本题的核心是理解“最后一次操作决定最终值”以及“多余的更新可以用任意字符填充”。通过贪心地为每个被更新的位置分配当前最小的字母作为最终值,并用最大的字母填充多余操作,即可得到字典序最小的结果。
- 1
信息
- ID
- 6987
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者