令\(S=\frac{1}{2}\sum_{i=1}^n|i-p_i|\),每次swap最好情况下会让 \(S\) 减少 \(2\),所以如果交换次数恰好是 \(\frac{1}{2}\sum_{i=1}^n|i-p_i|\),那么每个数都不能向 \(p_i\) 的反方向移动,也就是排序过程中,某个数字不能同时有往后和往前移动两个操作。
冒泡排序的过程是顺序比较每个数字和后面的数字,对于每个数字,如果往后移,前面肯定没有比它更大的数,所以这个数不会再往前移;如果往前移(前面有更大的数)同时后面有更小的数,这个数字就一定还会往后移。
所以一个序列不“好”的条件是存在某个位置 \(i\) 前面有比它更大的数,后面有比它更小的数,即这个序列中存在长度 \(>2\) 的下降子序列
不想写了,看 这篇博客吧(雾)
int a[MAXN >> 1], n;
inline Mod C(int n, int m) {
if (m > n) return 0;
return fac[n] * ifac[n - m] * ifac[m];
}
inline Mod Get(int n, int m) {
return C(n + m - 2, m - 1) - C(n + m - 2, m - 2);//(1,1)走到(n,m)方案数
}
void init() {
freopen("inverse.in", "r", stdin);
freopen("inverse.out", "w", stdout);
fac[0] = 1;
lop1(i, MAXN) fac[i] = fac[i - 1] * i;
ifac[MAXN - 1] = fac[MAXN - 1].inv();
dlop0(i, MAXN - 1) ifac[i] = ifac[i + 1] * (i + 1);
assert(ifac[0].a == 1);
}
void solve() {
static bitset<600005>vis;
n = in;
lop1(i, n) in, a[i];
int Min = 1, Max = 0;
vis.reset();
Mod ans = 0;
lop1(i, n) {
while (vis.test(Min)) ++Min;
int t = n - i + 1, res = n - max(a[i], Max);//可行集合大小
if (res > 1) ans += Get(t + 1, res);
else ans += res > 0; //(1, 1)到(n, 1)
if (Max > a[i] and a[i] > Min) break;//存在长度>2的下降子序列
chmax(Max, a[i]);
vis.set(a[i]);
}
out, ans.a, '\n';
}