P4769[NOI2018 冒泡排序] 题解

题面链接#

简要题意#

12i=1n|pii|= 冒泡排序最少交换次数 的排列 {pn} 的数量。

Lemmas#

Lemma 1#

冒泡排序最少交换次数等于逆序对数量

证明#

注意到冒泡排序的过程交换一次逆序对减少一

Lemma 2#

12i=1n|pii|=i=1nmax(ipi,0)

证明#

Obviously

Lemma 3#

x,i=1x[pi>px]max(xpx,0)

证明#

注意到当 xpx,LHS 最小时 [1,pi) 都在 [1,x) 内,此时 LHS=(x1)(px1)=xpxx<px 显然。

原命题的转化#

结合 Lemmas,我们要求满足对于每一个 x,满足 i=1x[pi>px]=max(xpx,0) 排列个数。考虑从小到大填数:若当前填到 x,将 x 填到位置 y,若 xy,那么必须有 x 要填到所有前面填的数的后面;否则 x>y,就必须有 i=1x[pi>px]=0,也就是 x 要填在当前排列第一个没有填数的位置。

综合以上的填数过程,可以发现如果我们将序列分成分别满足 pxxpx>x 的两部分,则两个部分是递增的,也就是说我们可以把满足题目条件的序列划分成两个上升子序列。

充分性易证。

即有原条件等价于排列可以划分成两个上升子序列。

答案统计#

考虑如何判断一个序列是否可以划分成两个上升子序列:考虑贪心地判断:考虑排列的前 i 位,可以分成两个上升子序列,其末尾分别是 x,y 满足 x<ypi+1=z,若 z<x,则无解,若 x<z<y,则 z 只能接在 x 后面,使 xz,否则 z>y,显然有将 z 接在 y 后面不劣于接在 x 后面,故使 yz

总结一下,我们把原序列的单调栈作为其中一个上升子序列,则剩下的子序列也是上升的就等价于原序列可以划分成两个上升子序列。

故我们这样设计状态:fi,j 表示考虑排列的前 i 位,最大值为 j 的数量。考虑转移:如果有 pi>max{p1,p2,...,pi1},那么有转移 fi1,kfi,pi(k<pi),否则考虑 S=[1,n]{p1,p2,...,pi1},则有 pi=min(S),所以 pi 的值唯一确定,有转移 fi1,jfi,j

综上,我们有 fi,j=k=1jfi1,k=fi1,j+fi,j1,要求满足 ij,最终答案为 fn,n

考虑枚举给定排列的前缀,如果要求排列的前 m 个数固定,为 a1,a2,...,am,令 mx=max{a1,a2,...,am},则有初值 fm,mx=1,注意到 dp 的过程相当于找到从 (m,mx)(n,n) 只能向上和向右走,且始终保持在直线 y=x 上方的路径的数量,参考卡特兰数的封闭形式,做一次关于 y=x1 的对称求出不满足条件的路径减掉即可,有封闭形式 (2nmmxnm)(2nmmxnm+1)。注意要判断当前前缀是否合法。

posted @   Watware  阅读(75)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示