[机房测试]冒泡排序期望
Description
一个长为 \(n\) 的排列的花费是使其排好序所要冒泡的次数。
for(int i=1;i<n;i++)
if(a[i]>a[i+1]) swap(a[i],a[i+1]);
求随机一个长为 \(n\) 的排列,花费的期望。
Solution
一个显然的做法是枚举花费,然后统计每种花费的排列个数。根据冒泡排序的性质,每次会使得最大的没有沉底的数沉底,如果对于一个数,前面存在比它大的,那么在一次排序操作后,个数一定会减一。定义 \(f_i\) 表示在 \(i\) 前面且比 \(i\) 大的数的个数,那么一个特定排列的花费就是 \(\max\{f_i\}\)、再次观察,可以发现,\(f\) 序列和实际排列构成一个双射关系。通过平衡树可以从大到小还原排列。也就是说,我们可以直接对 \(f\) 序列进行计数。那么只需要保证 \(\forall i,f_i\leq \min(i-1,k)\) 就行了。但这样求出来的实际上是 \(\max\{f_i\}\leq k\) 的方案,需要差分一下,就可以得到
\[f(n,k)=k!((k+1)^{n-k}-k^{n-k})
\]