1. 程式人生 > 其它 >CF1523E - Crypto Lights(概率dp,組合數學)

CF1523E - Crypto Lights(概率dp,組合數學)

題目

\(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盞燈點亮後不合法) \]

故答案為

\[\sum\limits_{i=1}^{n}{(g_i-g_{i+1})(i+1)} \]

考慮計算\(f_i\),即在1~n中選擇\(i\)個數\((1\le a_1< a_2<...<a_i \le n)\)使得它們之間間隔大於等於\(k\)的方案數。作差分有\(b_j=a_{j}-a_{j-1}\),那轉換為\(b_1 \ge 1\)\(b_j\ge 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 '\n'
#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;
	}
}