P4769[NOI2018 冒泡排序] 题解
题面链接
简要题意
求 \(\displaystyle{\frac{1}{2}\sum_{i=1}^n\lvert p_i-i\rvert}=\) 冒泡排序最少交换次数 的排列 \(\{p_n\}\) 的数量。
Lemmas
Lemma 1
冒泡排序最少交换次数等于逆序对数量
证明
注意到冒泡排序的过程交换一次逆序对减少一
Lemma 2
证明
Obviously
Lemma 3
证明
注意到当 \(x\ge p_x\),LHS 最小时 \([1,p_i)\) 都在 \([1,x)\) 内,此时 \(LHS=(x-1)-(p_x-1)=x-p_x\),\(x<p_x\) 显然。
原命题的转化
结合 Lemmas,我们要求满足对于每一个 \(x\),满足 \(\sum_{i=1}^x[p_i>p_x]= max(x-p_x,0)\) 排列个数。考虑从小到大填数:若当前填到 \(x\),将 \(x\) 填到位置 \(y\),若 \(x\le y\),那么必须有 \(x\) 要填到所有前面填的数的后面;否则 \(x>y\),就必须有 \(\sum_{i=1}^x[p_i>p_x]=0\),也就是 \(x\) 要填在当前排列第一个没有填数的位置。
综合以上的填数过程,可以发现如果我们将序列分成分别满足 \(p_x\le x\) 和 \(p_x>x\) 的两部分,则两个部分是递增的,也就是说我们可以把满足题目条件的序列划分成两个上升子序列。
充分性易证。
即有原条件等价于排列可以划分成两个上升子序列。
答案统计
考虑如何判断一个序列是否可以划分成两个上升子序列:考虑贪心地判断:考虑排列的前 \(i\) 位,可以分成两个上升子序列,其末尾分别是 \(x,y\) 满足 \(x<y\),\(p_{i+1}=z\),若 \(z<x\),则无解,若 \(x<z<y\),则 \(z\) 只能接在 \(x\) 后面,使 \(x\leftarrow z\),否则 \(z>y\),显然有将 \(z\) 接在 \(y\) 后面不劣于接在 \(x\) 后面,故使 \(y\leftarrow z\)。
总结一下,我们把原序列的单调栈作为其中一个上升子序列,则剩下的子序列也是上升的就等价于原序列可以划分成两个上升子序列。
故我们这样设计状态:\(f_{i,j}\) 表示考虑排列的前 \(i\) 位,最大值为 \(j\) 的数量。考虑转移:如果有 \(p_i>\max\{p_1,p_2,...,p_{i-1}\}\),那么有转移 \(f_{i-1,k}\rightarrow f_{i,p_i}(k<p_i)\),否则考虑 \(S=[1,n]\backslash \{p_1,p_2,...,p_{i-1}\}\),则有 \(p_i=\min(S)\),所以 \(p_i\) 的值唯一确定,有转移 \(f_{i-1,j}\rightarrow f_{i,j}\)。
综上,我们有 \(f_{i,j}=\displaystyle\sum_{k=1}^{j}f_{i-1,k}=f_{i-1,j}+f_{i,j-1}\),要求满足 \(i\le j\),最终答案为 \(f_{n,n}\)。
考虑枚举给定排列的前缀,如果要求排列的前 \(m\) 个数固定,为 \(a_1,a_2,...,a_m\),令 \(mx=\max\{a_1,a_2,...,a_m\}\),则有初值 \(f_{m,mx}=1\),注意到 dp 的过程相当于找到从 \((m,mx)\) 到 \((n,n)\) 只能向上和向右走,且始终保持在直线 \(y=x\) 上方的路径的数量,参考卡特兰数的封闭形式,做一次关于 \(y=x-1\) 的对称求出不满足条件的路径减掉即可,有封闭形式 \(\binom{2n-m-mx}{n-m}-\binom{2n-m-mx}{n-m+1}\)。注意要判断当前前缀是否合法。