zoukankan      html  css  js  c++  java
  • [NOI2018]冒泡排序 (卡特兰数)

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

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

    [f_{i,j}=sum_{k=j-1}^{i-1}f_{i-1,k} ]

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

    [sum_{j=k+1}^{n-i+1}f_{n-i+1,j} ]

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

    [S_{i,j}=sum_{k=j}^if_{i,k}=f_{i,j}+sum_{k=j+1}^if_{i,k}=S_{i-1,j-1}+S_{i,j+1} ]

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

    [S_{i,j}= {2i-jchoose i-j} - {2i-jchoose i-j-1} ]

    最后复杂度为(O(Nlog_2N))

  • 相关阅读:
    React入门实例
    【C语言】一些重要的知识点
    【C语言】字符串模块
    【C语言】指针模块
    贝尔曼福特算法
    dijkstra算法
    拓扑序列
    树和图的广度优先遍历
    树和图的深度优先遍历
    回溯剪枝,dfs,bfs
  • 原文地址:https://www.cnblogs.com/zzy2005/p/14000510.html
Copyright © 2011-2022 走看看