Processing math: 100%

[NOI2018]冒泡排序 (卡特兰数)

首先有一个性质,达到下界的充要条件是排不能存在长度大于2的下降子序列。
证明:
要想达到下界12|ipi|,等于每次交换相邻两个数时,这两个数一定是往目的方向移动。
如果存在长度大于2的下降子序列,那么第一次,对于这个子序列中的中间的一个数x,之前比x大的数一定会和它产生交换,它就会往前移动,而它又会和后面比它小的数交换,所以它也至少会往后移动一次。所以它一定会在中途产生“掉头”的代价。

有了这个性质后,我们问题变成求不存在长度大于2的下降子序列的排列数。
fi,j表示长度为i的排列,第一个数是j的方案数。
分几种情况转移:
如果第二个数k大于j,那么方案数就是fi1,k
如果第二个数k小于j,且不等于1,那么一定会存在为(j,k,1)这样的下降子序列,所以方案数为0
如果第二个数为1,那么小于j的数一定是依次排列的(位置可以不连续),且之后的方案我们可以对应一种合法的方案(1换到2 , 2换到3 ... , j1换到1),所以方案数为fi1,j1
综上,我们得到了:

fi,j=i1k=j1fi1,k

接下来,我们考虑字典序的问题。
我们枚举一个位置i,前i1位和输入序列一样,第i位比输入序列大。
首先第i位肯定不能填剩余的最小值。
再然后第i位不能比前i1位最大的小,如果这一位填k<mx,会和剩余最小值组成一个长度为3的下降子序列。
所以假设剩余有k个数比前i1位最大值小,
则方案数为

ni+1j=k+1fni+1,j

注意还要判断一下第i是否可行,具体看代码。
用树状数组求k,然后我们得到了一个O(N2logN)的做法。
考虑优化这个后缀和。

Si,j=ik=jfi,k=fi,j+ik=j+1fi,k=Si1,j1+Si,j+1

放到网格上来看,就是从(0,0)走到(i,j),每次能向右上,或者下走一次,不能越过x轴。
向下走有点奇怪,我们变成向右下走,那么就变成了从(0,0)走到(2ij,j)
有经验的选手能看出来,这就是卡特兰数。
用组合意义解释,就是在第一次碰到 y=1 时,把前面的线段翻折一下。

Si,j=(2ijij)(2ijij1)

最后复杂度为O(Nlog2N)

posted @   zzy2005  阅读(119)  评论(0编辑  收藏  举报
编辑推荐:
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
阅读排行:
· 我干了两个月的大项目,开源了!
· 推荐一款非常好用的在线 SSH 管理工具
· 千万级的大表,如何做性能调优?
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· .NET周刊【1月第1期 2025-01-05】
点击右上角即可分享
微信分享提示