CodeForces 1194F Crossword Expert (期望+组合数学)

题目链接:点击这里

题目大意:
n n n 个任务,每个任务需要 t i t_i ti t i + 1 t_i+1 ti+1 的时间完成,要按给出的顺序解决,求在 T T T 时间内,完成任务数的期望

题目分析:
设解决第 i i i 个任务的概率为 P i P_i Pi ,完成任务数的数期望为 E E E ,由题意可得:
E = ∑ i = 1 n i P i E=\sum_{i=1}^niP_i E=i=1niPi
= P 1 + P 2 + P 2 + P 3 + P 3 + P 3 + . . . =P_1+P_2+P_2+P_3+P_3+P_3+... =P1+P2+P2+P3+P3+P3+...
f i f_i fi 为最终完成任务数大于等于 i i i 的概率,有:
f i = ∑ k = i n P k f_i=\sum_{k=i}^nP_k fi=k=inPk
则此时有:
E = ∑ i = 1 n f i E=\sum_{i=1}^nf_i E=i=1nfi
接下来我们分类讨论一些情况:
s u m i = ∑ k = 1 i t i sum_i=\sum\limits_{k=1}^it_i sumi=k=1iti ,则前 i i i 个任务花费的最少时间为 s u m i sum_i sumi ,最长时间为 s u m i + i sum_i+i sumi+i

  1. s u m i > T sum_i>T sumi>T 时,说明不可能完成,应在此时 b r e a k break break
  2. s u m i + i ≤ T sum_i+i \le T sumi+iT ,说明此时一定能完成,此时有 f i = 1 f_i=1 fi=1
  3. s u m i ≤ T < s u m i + i sum_i \le T < sum_i+i sumiT<sumi+i ,此时至多有 T − s u m i T-sum_i Tsumi 个任务多花费了 1 1 1 分钟,因为我们枚举 1 1 1 T − s u m i T-sum_i Tsumi 用组合数就能统计出所有可能的方案数,而总方案数为 2 i 2^i 2i ,所以有:
    f i = ∑ k = 0 T − s u m i C i k 2 i f_i=\frac{\sum_{k=0}^{T-sum_i}C_i^k}{2^i} fi=2ik=0TsumiCik

所以有:
E = ∑ i = 1 n ∑ k = 0 T − s u m i C i k 2 i E=\sum_{i=1}^n\frac{\sum_{k=0}^{T-sum_i}C_i^k}{2^i} E=i=1n2ik=0TsumiCik
每次计算 f i f_i fi 用循环是会超时的,我们考虑优化组合数部分:
我们知道:
C n m + c n m + 1 = C n + 1 m + 1 C_n^m+c_n^{m+1}=C_{n+1}^{m+1} Cnm+cnm+1=Cn+1m+1
于是可以写这样一组方程:
{ C n + 1 0 = C n 0 C n + 1 1 = C n 0 + C n 1 C n + 1 2 = C n 1 + C n 2 . . . C n + 1 m − 1 = C n m − 2 + C n m − 1 C n + 1 m = C n m − 1 + C n m \left \{ \begin{array}{c} C_{n+1}^0=C_n^0\\ C_{n+1}^1=C_n^0+C_n^1\\ C_{n+1}^2=C_n^1+C_n^2\\ ...\\ C_{n+1}^{m-1}=C_n^{m-2}+C_n^{m-1}\\ C_{n+1}^m=C_n^{m-1}+C_n^m\\ \end{array} \right. Cn+10=Cn0Cn+11=Cn0+Cn1Cn+12=Cn1+Cn2...Cn+1m1=Cnm2+Cnm1Cn+1m=Cnm1+Cnm
两边累加可以得到:
∑ k = 0 m C n + 1 k = 2 ∑ k = 0 m C n k − C n m \sum_{k=0}^mC_{n+1}^k=2\sum_{k=0}^mC_n^k-C_n^m k=0mCn+1k=2k=0mCnkCnm
因为 T − s u m i T−sum_i Tsumi 是单调递减的,我们可以直接用上述公式又上一层转移到下一层

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
ll read()
{
	ll res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
ll n,T,t[maxn],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-1;i;i--)
		inv[i-1] = inv[i]*i%mod;
} 
ll C(int n,int m)
{
	if(m==0 || n==m) return 1;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll sigma,last;
ll get_res(int pos,ll rem)
{
	if(sigma == 0)
	{
		sigma = 1;
		for(int i = 1;i <= rem;i++)
			sigma = (sigma+C(pos,i))%mod;
		last = rem;
		return sigma;
	}
	sigma = (sigma*2-C(pos-1,last)+mod)%mod; //先转移
	for(int i = last;i >= rem+1;i--) //再把多余的减去
		sigma = (sigma-C(pos,i)+mod)%mod;
	last = rem;
	return sigma;
}
int main()
{
	init();
	n = read(),T = read();
	for(int i = 1;i <= n;i++)
		t[i] = read();
	ll sum = 0,base = 1,ans = 0;
	for(int i = 1;i <= n;i++)
	{
		sum += t[i];
		base = base*2%mod;
		if(T-sum >= i)
		{
			ans = (ans+1)%mod;
			continue;
		}
		if(T-sum < 0) break;
		ans = (ans+get_res(i,T-sum)*qpow(base,mod-2)%mod)%mod;
	}
	printf("%lld\n",ans);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值