题目
有(n)盏灯排成一排,初始时所有的灯是灭的。每次会等概率随机点亮一个灭的灯。如果存在连续(k)盏灯中有大于1盏灯是亮的,则结束。给定(n)和(k),问期望的灯的数量是多少。
题解
假设有(i)盏灯被点亮,那么它们的间隔均大于等于(k)。故(i)盏灯被点亮的顺序不重要,确定了这(i)盏灯的位置,任意一种取的顺序都是合法的。设(f_i)代表第(i)盏灯被点亮依旧合法的情况数,那么有(i)盏灯被点亮后依旧合法的概率(g_i)为
[g_i=(prod_{j=0}^{i-1}frac{1}{n-j} )i! cdot f_i
]
又有
[g_i=g_{i+1}+P(第i+1盏灯点亮后不合法)
]
故答案为
[sumlimits_{i=1}^{n}{(g_i-g_{i+1})(i+1)}
]
考虑计算(f_i),即在1~n中选择(i)个数((1le a_1< a_2<...<a_i le n))使得它们之间间隔大于等于(k)的方案数。作差分有(b_j=a_{j}-a_{j-1}),那转换为(b_1 ge 1),(b_jge k),(sum{b_j} le n)。直接转换为盒子放球模型解决,相当于(n-(i-1)cdot k)个球放入(i+1)个盒子,除了第1个盒子至少放一个,其余盒子可放可不放,有
[f_i=C(n-(i-1)cdot k + i - 1, i)
]
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const int M = 1e9 + 7;
const double eps = 1e-5;
ll fact[N], rfact[N];
inline ll qpow(ll a, ll b, ll m) {
ll res = 1;
while(b) {
if(b & 1) res = (res * a) % m;
a = (a * a) % m;
b = b >> 1;
}
return res;
}
ll C(int n, int m) {
if(m > n) return 0;
return fact[n] * rfact[n - m] % M * rfact[m] % M;
}
ll p[N];
int main() {
IOS;
fact[0] = rfact[0] = 1;
for(int i = 1; i < N; i++) {
fact[i] = fact[i - 1] * i % M;
rfact[i] = rfact[i - 1] * qpow(i, M - 2, M) % M;
}
int t;
cin >> t;
while(t--) {
int n, k;
cin >> n >> k;
for(int i = 1; i <= n + 1; i++) p[i] = 0;
ll pw = 1;
for(int i = 1; i <= n; i++) {
pw = pw * qpow(n - i + 1, M - 2, M) % M;
int ret = n - (i - 1) * k;
if(ret < 0) break;
p[i] = C(ret + i - 1, i) * pw % M * fact[i] % M;
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
ans = (ans + (i + 1) * (p[i] - p[i + 1]) % M + M) % M;
}
cout << ans << endl;
}
}