CF1523E (概率+组合数学)

6 篇文章 0 订阅

题目大意:

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=1npii

  • 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=1npii=i=1nj=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=1npii=p1+2p2+...+npn=(p1+...+pn)+(p2+...+pn)+...+(pn)=i=1nj=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=1n1gi

  • 那么 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)} iniik1iniii1i+1a+x1+x2+...+xi1+b=nia0,b0,xjk1(j[1,i1])ni+2ni+2(i1)(k2)i,C(n(i1)(k1),i)gi=C(n,i)C(n(i1)(k1),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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值