[NOI2018]冒泡排序 (卡特兰数)
首先有一个性质,达到下界的充要条件是排不能存在长度大于2的下降子序列。
证明:
要想达到下界12∑|i−pi|,等于每次交换相邻两个数时,这两个数一定是往目的方向移动。
如果存在长度大于2的下降子序列,那么第一次,对于这个子序列中的中间的一个数x,之前比x大的数一定会和它产生交换,它就会往前移动,而它又会和后面比它小的数交换,所以它也至少会往后移动一次。所以它一定会在中途产生“掉头”的代价。
有了这个性质后,我们问题变成求不存在长度大于2的下降子序列的排列数。
设fi,j表示长度为i的排列,第一个数是j的方案数。
分几种情况转移:
如果第二个数k大于j,那么方案数就是fi−1,k。
如果第二个数k小于j,且不等于1,那么一定会存在为(j,k,1)这样的下降子序列,所以方案数为0。
如果第二个数为1,那么小于j的数一定是依次排列的(位置可以不连续),且之后的方案我们可以对应一种合法的方案(1换到2 , 2换到3 ... , j−1换到1),所以方案数为fi−1,j−1
综上,我们得到了:
接下来,我们考虑字典序的问题。
我们枚举一个位置i,前i−1位和输入序列一样,第i位比输入序列大。
首先第i位肯定不能填剩余的最小值。
再然后第i位不能比前i−1位最大的小,如果这一位填k<mx,会和剩余最小值组成一个长度为3的下降子序列。
所以假设剩余有k个数比前i−1位最大值小,
则方案数为
注意还要判断一下第i是否可行,具体看代码。
用树状数组求k,然后我们得到了一个O(N2logN)的做法。
考虑优化这个后缀和。
放到网格上来看,就是从(0,0)走到(i,j),每次能向右上,或者下走一次,不能越过x轴。
向下走有点奇怪,我们变成向右下走,那么就变成了从(0,0)走到(2i−j,j)。
有经验的选手能看出来,这就是卡特兰数。
用组合意义解释,就是在第一次碰到 y=−1 时,把前面的线段翻折一下。
最后复杂度为O(Nlog2N)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
· 我干了两个月的大项目,开源了!
· 推荐一款非常好用的在线 SSH 管理工具
· 千万级的大表,如何做性能调优?
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· .NET周刊【1月第1期 2025-01-05】