CF1523E Crypto Lights

空気力学の詩發表於2024-08-14

小清新 Counting,被徐神絕殺力

直觀地想我們需要求出恰好 \(m\) 輪結束的機率 \(p(m)\),但這個顯然不好直接求,我們退而求其次

用經典 trick,我們設 \(f(m)\) 表示至少點亮了 \(m\) 盞燈的機率,最後求和得到的就是帶權的機率和也就是期望

考慮 \(f(m)\) 如何計算,轉為計算合法局面的方案數,即在 \(n\) 個白球中選出 \(m\) 個球塗色,滿足任意兩個有色球之間的距離 \(\ge k\)

徐神賽時用的是捆綁法,即將一個有色球和右側的 \(k-1\) 個無色球看成一個整體來考慮;我當時想了一個插板法的做法不過好像大差不差,最後得到的式子為:

\[f(m)=\frac{C_{n-(m-1)\times (k-1)}^{m}}{C_n^m} \]

#include <bits/stdc++.h>

using llsi = long long signed int;
constexpr llsi mod = 1'000'000'007;

llsi ksm(llsi a, llsi b) {
    llsi res = 1;
    while(b) {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

llsi fac[100005], facinv[100005];

void init(int n = 100000) {
    fac[0] = 1;
    for(int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % mod;
    facinv[n] = ksm(fac[n], mod - 2);
    for(int i = n; i >= 1; --i) facinv[i - 1] = facinv[i] * i % mod;
    return ;
}

inline llsi C(llsi a, llsi b) {
    return fac[a] * facinv[b] % mod * facinv[a - b] % mod;
}

llsi f[100005];

void work() {
    llsi n, k;
    std::cin >> n >> k;
    memset(f, 0, sizeof(llsi) * (n + 1));
    f[0] = 1;
    // for(llsi i = 0; i <= n; ++i) std::cerr << f[i] << char(i == n ? 10 : 32);
    for(llsi m = 1; m <= n; ++m) {
        llsi t = (m - 1) * (k - 1);
        if(t > n || n - t < m) f[m] = 0;
        else                   f[m] = C(n - t, m) * ksm(C(n, m), mod - 2) % mod;
    }
    // for(llsi i = 0; i <= n; ++i) std::cerr << f[i] << char(i == n ? 10 : 32);
    llsi ans = 0;
    for(llsi i = 0; i <= n; ++i)
        ans += f[i];

    std::cout << ans % mod << char(10);
    return ;
}

int main() {
    std::ios::sync_with_stdio(false);
    init();
    int t; std::cin >> t; while(t--) work();
    return 0;
}

相關文章