题目大意:
n n n盏灯,每次随机从熄灭的灯中选择一盏变亮,当连续有 k k k个灯大于一盏亮着,则结束,求最终期望开灯次数
解题思路:
-
设 p i p_i pi为第 i i i次就结束的期望, a n s = ∑ i = 1 n p i ⋅ i ans=\sum_{i=1}^{n}p_i \cdot i ans=∑i=1npi⋅i
-
a n s = ∑ i = 1 n p i ⋅ i = ∑ i = 1 n ∑ j = i n p j ans=\sum_{i=1}^{n}p_i\cdot i =\sum_{i=1}^{n}\sum_{j=i}^{n}p_j ans=∑i=1npi⋅i=∑i=1n∑j=inpj
-
对于 ∑ i = 1 n p i ⋅ i = p 1 + 2 p 2 + . . . + n p n = ( p 1 + . . . + p n ) + ( p 2 + . . . + p n ) + . . . + ( p n ) = ∑ i = 1 n ∑ j = i n p j \sum_{i=1}^{n}p_i\cdot i=p_1+2p_2+...+np_n=(p_1+...+p_n)+(p_2+...+p_n)+...+(p_n)=\sum_{i=1}^{n}\sum_{j=i}^{n}p_j ∑i=1npi⋅i=p1+2p2+...+npn=(p1+...+pn)+(p2+...+pn)+...+(pn)=∑i=1n∑j=inpj
-
令 g i = ∑ j = i + 1 n p j g_i=\sum_{j=i+1}^{n}p_j gi=∑j=i+1npj
-
g i g_i gi的含义就是,选择了 i i i次还没有结束的期望
-
所以最后答案就是: ∑ i = 1 n − 1 g i \sum_{i=1}^{n-1}g_i ∑i=1n−1gi
-
那么 g i g_i gi如何算呢,利用隔板法:
选 择 了 i 次 还 没 结 束 等 价 n 个 空 中 选 了 i 个 空 放 球 , 这 i 个 球 相 邻 之 间 的 距 离 至 少 为 k − 1 因 为 有 i 个 空 被 选 择 还 剩 n − i 个 空 未 被 选 择 , 而 i 个 球 之 间 的 空 隙 有 i − 1 个 , 再 加 上 两 边 的 空 袭 有 i + 1 个 空 隙 写 成 式 子 如 下 : a + x 1 + x 2 + . . . + x i − 1 + b = n − i a ≥ 0 , b ≥ 0 , x j ≥ k − 1 ( j ∈ [ 1 , i − 1 ] ) 所 以 就 相 当 于 先 : n − i + 2 然 后 : n − i + 2 − ( i − 1 ) ∗ ( k − 2 ) 从 这 里 面 选 i 个 空 , 隔 板 一 下 就 好 合 法 方 案 数 为 : C ( n − ( i − 1 ) ∗ ( k − 1 ) , i ) g i = C ( n − ( i − 1 ) ∗ ( k − 1 ) , i ) C ( n , i ) 选择了i次还没结束等价n个空中选了i个空放球,这i个球相邻之间的距离至少为k-1 \\ 因为有i个空被选择还剩n-i个空未被选择,而i个球之间的空隙有i-1个,再加上两边的空袭有i+1个空隙 \\ 写成式子如下: \\ a+x_1+x_2+...+x_{i-1}+b=n-i \\ a \ge 0, b\ge 0, x_j\ge k-1(j \in[1,i-1]) \\ 所以就相当于先:n-i+2 \\ 然后:n-i+2-(i-1)*(k-2)从这里面选i个空,隔板一下就好 \\ 合法方案数为:C(n-(i-1)*(k-1),i) \\ g_i=\frac{C(n-(i-1)*(k-1),i)}{C(n,i)} 选择了i次还没结束等价n个空中选了i个空放球,这i个球相邻之间的距离至少为k−1因为有i个空被选择还剩n−i个空未被选择,而i个球之间的空隙有i−1个,再加上两边的空袭有i+1个空隙写成式子如下:a+x1+x2+...+xi−1+b=n−ia≥0,b≥0,xj≥k−1(j∈[1,i−1])所以就相当于先:n−i+2然后:n−i+2−(i−1)∗(k−2)从这里面选i个空,隔板一下就好合法方案数为:C(n−(i−1)∗(k−1),i)gi=C(n,i)C(n−(i−1)∗(k−1),i)
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int t, n, k;
ll fac[maxn], inv[maxn];
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void init() {
fac[0] = 1;
for (int i = 1; i < maxn; i++) fac[i] = fac[i - 1] * i % mod;
inv[maxn - 1] = qpow(fac[maxn - 1], mod - 2);
for (int i = maxn - 2; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll C(ll n, ll m) {
if (m > n) return 0;
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int main() {
init();
cin >> t;
while (t--) {
ll ans = 1;
cin >> n >> k;
for (int i = 1; i <= n; i++)
ans = (ans + C(n - 1ll * (i - 1) * (k - 1), i) * qpow(C(n, i), mod - 2) % mod) % mod;
cout << ans << endl;
}
return 0;
}