拼接字符串要求字典序最小

好唐啊,这种题我目前已经知道三道一样的了,无聊记录一下。

传递性可以通过 题解:P1012 [NOIP 1998 提高组] 拼数 中的转小数来证明,而最优性就是,我们本来就考虑的相邻两个 \(i,j\) 谁在前面更优,显然把,当然我当时的题解里的理解方法也许也能参考。

CF632C - The Smallest String Concatenation & luogu - P1012 [NOIP 1998 提高组] 拼数 & [ABC225F] String Cards(这题排序后,从后往前 dp 即可,但是从前往后 dp 也行,不过还得背个长度)

[ABC434F] Concat (2nd)

一道题。

\(n\) 个字符串,给字符串安排顺序并拼接,可以获得 \(n!\) 个字符串,求这 \(n!\) 个字符串按字典序从小到大排序后的第二个。

多测,\(1 \le T \le 1.5 \cdot 10^5\)\(2 \le n \le 3 \cdot 10^5\)\(\sum\limits n \le 3 \cdot 10^5\)\(\sum\limits{|s|} \le 10^6\)\(s\) 只由小写英文字母构成,1s & 1GB。

最小的是好求的,按照 \(s_i + s_j < s_j + s_i\) 排序即可,嘶,这个排序的时间复杂度怎样?

  • 先明确最坏情况下是 \(O(n \log n \max\limits_{i=1}^{n}{|s|})\)
  • 先来了解一下 c++STL 中 sort 和 stable_sort 分别是怎么排序的:
    • sort
      • 快速排序:作为主要排序算法,平均性能好
      • 堆排序:当递归深度过大时切换到堆排序,保证 \(O(n \log n)\) 的最坏时间复杂度
      • 插入排序:对于小子序列(通常 \(\le 16\) 个元素)使用插入排序
    • stable_sort
      • 使用的归并排序的变种。
      • 如果内存充足,使用标准的归并排序。
      • 如果内存不足,使用原地归并或外部归并的变种。
  • 考虑 shuffle 一下,可以感性理解每个字符串的比较次数是相等的,时间复杂度 \(O(\sum\limits{|s|} \log n)\)
    • 这篇题解 Link 里是把快速排序复杂度给算了一遍,有点宝宝,我也不太会解释这个东西,有没有大蛇解释的。
  • 当然还可以二分哈希。

现在考虑次小的,假设已经给字符串排序了:

  • 如果一对相邻的 \(a+b=b+a\) 次小就是最小。
  • 如果多次交换(\(\ge 2\) 次)肯定不是次小,好理解。
  • 如果交换不想临的位置,肯定不是次小,也好理解。
  • 所以有关次小的问题,可以从多个角度入手,结合得出结论,因为次小的性质极多。

只剩下 \(n-1\) 种字符串了,看上去还不够啊,继续玩。

  • 考虑翻转最后两个得到的字符串 \(B\) 和最小字符串 \(A\),如果 \(B\) 不是次小,次小一定在 \(A,B\) 之间,即前 \(n-2\) 个字符串必须得是这样。
  • 所以只剩下了,翻转 \(n-1,n\) 的和翻转 \(n-2,n-1\) 的了,比较即可。
posted @ 2025-10-14 21:48  hhhqx  阅读(10)  评论(0)    收藏  举报