• CF1523E


    题目

    (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;
    	}
    }
    
  • 相关阅读:
    【阿里云产品评测】装甲兵在云路上!
    区间交集问题
    信封嵌套问题
    twoSum问题的核心思想
    队列实现栈|栈实现队列
    设计Twitter 时间线
    如何使用单调栈解题
    二叉堆详解实现优先级队列
    git/SQL/正则表达式的在线练习网站
    我的 Redis 被入侵了
  • 原文地址:https://www.cnblogs.com/limil/p/15246526.html
Copyright © 2020-2023  润新知