小清新 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;
}