【CF1523E】Crypto Lights

题目

题目链接:https://codeforces.com/contest/1523/problem/E
\(n\) 个台灯初始时都是暗的,每次等概率随机一个暗台灯将其点亮,若点亮后存在一个长度为 \(k\) 的连续段有大于一个台灯被点亮则立刻停止,求期望点亮多少台灯。答案对 \(10^9+7\) 取模。
\(2\leq n,k\leq 10^5\)

思路

\(f_i\) 表示选择 \(i\) 次后结束的期望。那么答案

\[=\sum^{n}_{i=1}f_i\times i=\sum^{n}_{i=1}\sum^{n}_{j=i}f_i \]

考虑如何求出 \(g_i=\sum^{n}_{j=i+1}f_i\)。也就是至少选择 \(i+1\) 次后才停止的期望。
显然 \(g_i\) 等价于选择了 \(i\) 次依然没有停止的期望。那么问题转化为有 \(n\) 个灯,选择其中 \(i\) 个,两两之间距离大于等于 \(k-1\) 的期望。
我们可以把每一个灯看做一个长度为 \(k\) 的线段,那么就是选择 \(i\) 个长度为 \(k\) 的区间互相不交。注意最后一个区间的右端点是可以超过 \(n\) 的。
那么我们直接把每一个区间的后 \(k-1\) 个元素删掉,问题转化为在 \(n-(i-1)(k-1)\) 个灯中选择 \(i\) 个的方案数。这个东西和刚刚的模型是等价的。假设现在的模型中选择了 \(i,j(i<j)\) 为相邻两盏灯,那么原模型中这两盏灯之间的距离就是 \(j-i+k-1\)
所以有

\[g_i=\frac{\binom{n-(i-1)(k-1)}{i}}{\binom{n}{i}} \]

答案就是 \(\sum^{n-1}_{i=0}g_i\)
时间复杂度 \(O(Qn)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=100010,MOD=1e9+7;
int Q,n,k,ans,fac[N],inv[N];

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

ll C(ll n,int m)
{
	if (n<m) return 0;
	return 1LL*fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}

ll invC(int n,int m)
{
	if (n<m) return 0;
	return 1LL*inv[n]*fac[m]%MOD*fac[n-m]%MOD;
}

int main()
{
	fac[0]=inv[0]=1;
	for (int i=1;i<N;i++)
		fac[i]=1LL*fac[i-1]*i%MOD;
	inv[N-1]=fpow(fac[N-1],MOD-2);
	for (int i=N-2;i>=1;i--)
		inv[i]=1LL*inv[i+1]*(i+1)%MOD;
	scanf("%d",&Q);
	while (Q--)
	{
		scanf("%d%d",&n,&k);
		ans=1;
		for (int i=1;i<n;i++)
			ans=(ans+C(n-1LL*(i-1)*(k-1),i)*invC(n,i))%MOD;
		cout<<ans<<"\n";
	}
	return 0;
}
posted @ 2021-06-11 15:33  stoorz  阅读(94)  评论(0编辑  收藏  举报