CF1096F Inversion Expectation(待更新)

题目地址:洛谷CF1096F

题意:求期望逆序对

记-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;
}

猜你喜欢

转载自www.cnblogs.com/xht37/p/10198314.html