[ARC104E] Random LIS 题解

发布时间 2023-11-03 18:53:43作者: User-Unauthorized

题意

给定一个长度为 \(N\) 的序列 \(A\),按照下列方式生成一个长度为 \(N\) 的序列 \(X\)
\(\forall i\in[1,n]\)\(X_i\)\([1,A_i]\) 中的整数中均匀随机生成。

求其最长上升子序列长度的期望,对 \(10^9+7\) 取模。

\(1 \le N \le 6, 1 \le A_i \le 10^9\)

题解

由于 \(N\) 很小,故我们可以直接枚举 \(X_i\) 的排名,然后计算其贡献。

发现并非所有的 \(N^N\) 种情况都是合法的,例如当 \(N = 3\) 时,排名序列 \(\left\{1,1,3\right\}\) 就是不合法的,而排名序列 \(\left\{1,1,2\right\}\) 是合法的。所有可能的合法排名序列叫做有序贝尔数,其 OEIS 编号为 A000670。当 \(N = 6\) 时,其值为 \(4683\)

现在问题变为了,在钦定的排名序列下,求最长上升子序列的长度和取到该排名的序列的方案数。

前者是平凡的,由于 \(N\) 很小,故可以肆意求。

现在考虑如何求方案数,首先我们可以将排名相同的数视为一类数,设我们有 \(M\) 类书,那么对于每一类数我们可以求出其最大取值为多少,设其为 \(H_i\),其中 \(H_0 = 0\),那么我们可以得出随着排名递减 \(H_i\) 应也为递减的,即 \(\forall i \in \left[1, M\right), H_i \le H_{i + 1}\),若存在 \(i \in \left[1, M\right)\),使得$ H_i > H_{i + 1}$,那么更新 \(H_i \leftarrow \min\left\{H_i, H_{i + 1}\right\}\) 即可。

可以发现数的取值范围是 \(\mathcal{O}(M)\) 个区间,故我们可以按区间去考虑,设 \(f_{i, j}\) 表示前 \(i\) 个区间中有 \(j\) 个数的方案数,通过枚举前 \(i - 1\) 个区间中有多少个数即可实现转移,因为钦定了前 \(i - 1\) 个区间中有多少个数,不妨设其为 \(k\),那么区间 \(\left(H_{i - 1}, H_{i}\right]\) 中的数有 \(j - k\) 种,其方案数为 \(\dbinom{H_{i} - H_{i - 1}}{j - k}\),至此可以写出转移式

\[f_{i, j} = \sum\limits_{k = i - 1}^{j} \dbinom{H_{i} - H_{i - 1}}{j - k} f_{i - 1, k} \]

初始状态为 \(f_{0, 0} = 1\),答案状态为 \(f_{M, M}\),这部分的复杂度为 \(\mathcal{O}(N^3)\)

\(a(N)\) 表示有序贝尔数,那么总复杂度为 \(\mathcal{O}(N^{N + 1} + a(N) N^3)\),肆意通过。

Code

#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

namespace MODINT {
    constexpr valueType MOD = 1e9 + 7;

    template<typename T1, typename T2, typename T3 = valueType>
    void Inc(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a + b;

        if (a >= mod)
            a -= mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Dec(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a - b;

        if (a < 0)
            a += mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sum(T1 a, T2 b, const T3 &mod = MOD) {
        return a + b >= mod ? a + b - mod : a + b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sub(T1 a, T2 b, const T3 &mod = MOD) {
        return a - b < 0 ? a - b + mod : a - b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 mul(T1 a, T2 b, const T3 &mod = MOD) {
        return (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Mul(T1 &a, T2 b, const T3 &mod = MOD) {
        a = (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 pow(T1 a, T2 b, const T3 &mod = MOD) {
        T1 result = 1;

        while (b > 0) {
            if (b & 1)
                Mul(result, a, mod);

            Mul(a, a, mod);
            b = b >> 1;
        }

        return result;
    }
}// namespace MODINT

using namespace MODINT;

valueType N, ans;
ValueVector A;

namespace MATH {
    ValueVector Fact, InvFact;

    void init(valueType n) {
        Fact.resize(n + 1);
        Fact[0] = 1;
        for (valueType i = 1; i <= n; ++i)
            Fact[i] = mul(Fact[i - 1], i);

        InvFact.resize(n + 1);
        InvFact[n] = pow(Fact[n], MOD - 2);
        for (valueType i = n - 1; i >= 0; --i)
            InvFact[i] = mul(InvFact[i + 1], i + 1);
    }

    valueType C(valueType n, valueType m) {
        valueType result = 1;

        for (valueType i = 0; i < m; ++i)
            Mul(result, (n - i) % MOD);

        Mul(result, InvFact[m]);

        return result;
    }
}// namespace MATH

using MATH::C;

bool check(ValueVector const &rank) {
    ValueVector copy(rank.begin(), rank.begin() + N + 1);

    std::sort(copy.begin(), copy.end());

    for (valueType i = 1; i <= N; ++i)
        if (copy[i] - copy[i - 1] > 1)
            return false;

    return true;
}

valueType length(ValueVector const &rank) {
    ValueVector F(N + 1, 0);
    valueType result = 0;

    for (valueType i = 1; i <= N; ++i)
        for (valueType j = 0; j < i; ++j)
            if (rank[i] > rank[j])
                result = std::max(result, F[i] = std::max(F[i], F[j] + 1));

    return result;
}

valueType calc(ValueVector const &rank) {
    valueType const M = *std::max_element(rank.begin(), rank.end());

    ValueVector limit(M + 1, std::numeric_limits<valueType>::max());

    for (valueType i = 1; i <= N; ++i)
        limit[rank[i]] = std::min(limit[rank[i]], A[i]);

    for (valueType i = M - 1; i >= 0; --i)
        limit[i] = std::min(limit[i], limit[i + 1]);

    limit[0] = 0;

    ValueMatrix F(M + 1, ValueVector(M + 1, 0));

    F[0][0] = 1;

    for (valueType i = 1; i <= M; ++i) {            // 前 i 段
        for (valueType j = i; j <= M; ++j) {        // 放了 j 种数
            for (valueType k = i - 1; k <= j; ++k) {// 前 i - 1 段放了 j 种数
                Inc(F[i][j], mul(F[i - 1][k], C(limit[i] - limit[i - 1], j - k)));
            }
        }
    }

    return F[M][M];
}

namespace DFS {
    ValueVector rank;

    void init(valueType n) {
        rank.resize(n + 1);
    }

    void dfs(valueType x) {
        if (x > N) {
            if (check(rank))
                Inc(ans, mul(length(rank), calc(rank)));

            return;
        }

        for (valueType i = 1; i <= N; ++i) {
            rank[x] = i;

            dfs(x + 1);
        }
    }
}// namespace DFS

using DFS::dfs;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::cin >> N;

    MATH::init(N);
    DFS::init(N);

    A.resize(N + 1);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> A[i];

    dfs(1);

    for (valueType i = 1; i <= N; ++i)
        Mul(ans, pow(A[i] % MOD, MOD - 2));

    std::cout << ans << std::endl;

    return 0;
}