LINK

题意

n n n盏熄灭的灯,每次操作在熄灭的灯随机选择一盏灯打开

当任意连续 k k k个灯至少有 2 2 2盏灯被打开游戏结束

求游戏结束的期望操作次数。


对于一个打开 w w w盏灯结束游戏的方案,考虑分别计算它的 w w w次贡献

分别是第 1 , 2 , . . . w 1,2,...w 1,2,...w次打开灯的贡献


基于这样的思想,我们考虑枚举一个 p p p表示当前点亮了 p p p盏灯

考虑计算此时游戏没有终止的方案数记作 f f f

那么对期望的贡献即为 f ∗ p ! n ∗ ( n − 1 ) . . . ∗ ( n − p + 1 ) f*\frac{p!}{n*(n-1)...*(n-p+1)} fn(n1)...(np+1)p!

如何计算 f f f呢??

这个问题的实质是,选出 p p p盏灯点亮,使得任意两盏亮灯中间至少有 k − 1 k-1 k1盏熄灭的灯

那么选出 p p p盏灯点亮,其余熄灭的灯形成 p + 1 p+1 p+1个连通块

我们只需要考虑让中间 p − 1 p-1 p1个连通块大小大于等于 k − 1 k-1 k1即可(这样两端也必定满足)

相当于我们先从中抽出 ( p − 1 ) ∗ ( k − 1 ) (p-1)*(k-1) (p1)(k1)盏灯,然后从剩下的灯任意选 p p p盏灯

方案数为 ( n − ( p − 1 ) ∗ ( k − 1 ) p ) {n-(p-1)*(k-1)\choose p} (pn(p1)(k1))

可以这么想,假设现在只有 n − ( p − 1 ) ∗ ( k − 1 ) n-(p-1)*(k-1) n(p1)(k1)盏灯,从中选择 p p p盏灯点亮

最后,在相邻两个被点亮的灯中间插入 k − 1 k-1 k1盏熄灭的灯

于是,答案为

1 + ( n − ( p − 1 ) ∗ ( k − 1 ) p ) ∗ p ! n ∗ ( n − 1 ) . . . ∗ ( n − p + 1 ) 1+{n-(p-1)*(k-1)\choose p}*\frac{p!}{n*(n-1)...*(n-p+1)} 1+(pn(p1)(k1))n(n1)...(np+1)p!

注意不要忘了加 1 1 1,因为对于任何一个操作次数为 w w w的方案来说

我们只计算了它的前 w − 1 w-1 w1步,没有计算最后那一步–终止的那一步

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
const int mod = 1e9+7;
#define int long long
int fac[maxn],n,m;
int quick(int x,int n)
{
	int ans = 1;
	for( ; n ; n>>=1,x=x*x%mod )
		if( n&1 )	ans = ans*x%mod;
	return ans;
}
int C(int n,int m)
{
	if( n<=0 || m>n )	return 0ll;
	return fac[n]*quick( fac[m]*fac[n-m]%mod,mod-2 )%mod;
}
signed main()
{
	fac[0] = 1;
	for(int i=1;i<=2000000;i++)	fac[i] = fac[i-1]*i%mod;
	int t; cin >> t;
	while( t-- )
	{
		int n,k; scanf("%lld%lld",&n,&k);
		int ans = 1;
    	for(int i=1;i<=n;i++)
		{	
			int f = C(n-(i-1)*(k-1),i );
			int p = fac[i]*quick( fac[n]*quick(fac[n-i],mod-2)%mod,mod-2 )%mod;
			ans = ( ans+f*p%mod )%mod;
		}
		cout << ans << endl;
	}
}