题意:求期望逆序对
记-1的个数为tot
分四种情况考虑:
Case 1:tot个数都不知道,显然期望逆序对为tot*(tot-1)/4;
Case 2,3:两个数中一个数知道一个数不知道
对于Case 2,左边的数不知道右边的数知道
Case 3同理且算法类似
设第x个数知道,记1~x-1中不知道的数的个数为s,所有未出现的数中比第x个数的值大的数的个数为k
显然期望逆序对为s*k/tot
Case 4:n-tot个数都知道,显然期望逆序对即为逆序对个数,用树状数组或者归并排序均可求解
把四种情况的期望逆序对相加即为ans
代码实现时可先用树状数组计算Case 4,这样Case2,3的单个计算就是O(logn)的了
总时间复杂度为O(nlogn)
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200006, P = 998244353;
int n, tot, a[N], s[N], c[N];
bool v[N];
void add(int x, int y) {
while (x <= n) {
c[x] += y;
x += x & -x;
}
}
int ask(int x) {
int ans = 0;
while (x) {
ans += c[x];
x -= x & -x;
}
return ans;
}
int ksm(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) ans = (ll)ans * a % P;
a = (ll)a * a % P;
b >>= 1;
}
return ans;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
s[i] = s[i-1] + (a[i] == -1);
if (a[i] == -1) ++tot;
}
int ans = (ll)tot * (tot - 1) % P * ksm(4, P - 2) % P;
for (int i = n; i; i--)
if (a[i] != -1) {
ans = (ans + ask(a[i] - 1)) % P;
add(a[i], 1);
}
int inv = ksm(tot, P - 2);
for (int i = 1; i <= n; i++)
if (a[i] != -1) {
ans = (ans + (ll)s[i] * (tot - a[i] + ask(a[i])) % P * inv % P) % P;
ans = (ans + (ll)(tot - s[i]) * (a[i] - ask(a[i])) % P * inv % P) % P;
}
cout << (ans + P) % P << endl;
return 0;
}