AT_agc023_e [AGC023E] Inversions 题解

设 $c_i=\sum\limits_{j=1}^n[a_j\ge i]-n+i$ 表示 $i$ 可选的位置数,

则符合要求的排列共有 $s=\prod\limits_{i=1}^nc_i$ 种,若 $\exists c_i=0$ 显然答案为 $0$。

考虑每对位置 $i,j|i<j$ 在多少排列中是逆序对。先考虑 $a_i\le a_j$ 的情况。

此时 $p_j<p_i\le a_i$,于是令 $a_j\gets a_i$,发现此时 $i,j$ 是逆序对与顺序对的方案数相等,且 $\forall k\in(a_i,a_j],c_k$ 减少 $1$,

所以此时 $i,j$ 在 $\dfrac S2\prod\limits_{k=a_i+1}^{a_j}\dfrac{c_k-1}{c_k}$ 个排列中是逆序对。

考虑预处理 $d_i=\prod\limits_{j=1}^i\dfrac{c_j-1}{c_j}$,则 $\dfrac S2\prod\limits_{k=a_i+1}^{a_j}\dfrac{c_k-1}{c_k}=\dfrac {Sd_{a_j}}{2d_{a_i}}$ 吗?

实际上并不是,考虑 $\dfrac{c_k-1}{c_k}\ne 0$,而 $d_{a_i},d_{a_j}$ 中有 $0$ 的情况。

改变 $d_i$ 的定义为 $d_i=\prod\limits_{j=1,c_j\ne 1}^i\dfrac{c_j-1}{c_j}$,设 $l_i$ 表示 $i$ 前第一个 $c_i=1$ 的位置,

考虑枚举 $j$,则 $j$ 的贡献为 $\dfrac S2\sum\limits_{i=l_{a_j}}^{a_j}\prod\limits_{k=i+1}^{a_j}\dfrac{c_k-1}{c_k}=\dfrac S2\sum\limits_{i=l_{a_j}}^{a_j}\dfrac{d_{a_j}}{d_i}$,此时保证了 $i\ge l_{a_j}$,所以式子成立。

$a$ 值为 $i$ 的位置要求在 $j$ 之前,所以树状数组维护。

$a_i>a_j$ 倒着做一遍。

#include <cstdio>
#include <cstring>
#define M 1000000007
#define int long long
int n, s, q, a[200050], c[200050], d[200050], l[200050];
int P(int x, int y)
{
    int q = 1;
    for (; y; y >>= 1, x = x * x % M)
        if (y & 1)
            q = q * x % M;
    return q;
}
struct T
{
    int c[200050];
    void C(int x, int k)
    {
        for (; x <= n; x += x & -x)
            c[x] = (c[x] + k) % M;
    }
    int Q(int x, int y)
    {
        int q = 0;
        for (x -= !!x; y > x; y &= y - 1)
            q = (q + c[y]) % M;
        for (; x > y; x &= x - 1)
            q = (q + M - c[x]) % M;
        return q;
    }
} C, D;
signed main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%lld", a + i), ++c[a[i]];
    for (int i = n; i; --i)
        c[i] += c[i + 1];
    for (int i = 1; i <= n; ++i)
        if (!(c[i] -= n - i))
            return !puts("0");
    d[0] = s = 1;
    for (int i = 1; i <= n; ++i)
    {
        s = s * c[i] % M;
        d[i] = d[i - 1] * P(c[i], M - 2) % M;
        if (c[i] == 1)
            l[i] = i;
        else
            d[i] = d[i] * (c[i] - 1) % M, l[i] = l[i - 1];
    }
    for (int i = 1; i <= n; ++i)
        q = (q + s * P(2, M - 2) % M * d[a[i]] % M * C.Q(l[a[i]], a[i])) % M, C.C(a[i], P(d[a[i]], M - 2));
    memset(C.c, 0, sizeof C.c);
    for (int i = n; i >= 1; --i)
        q = (q + s * D.Q(1, a[i] - 1) % M + M - s * P(2, M - 2) % M * d[a[i]] % M * C.Q(l[a[i]], a[i] - 1) % M) % M, C.C(a[i], P(d[a[i]], M - 2)), D.C(a[i], 1);
    printf("%lld", q);
    return 0;
}
posted @ 2023-08-22 09:59  5k_sync_closer  阅读(6)  评论(0编辑  收藏  举报  来源