题目链接:点击这里
题目大意:
有
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=1∑niPi
=
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=i∑nPk
则此时有:
E
=
∑
i
=
1
n
f
i
E=\sum_{i=1}^nf_i
E=i=1∑nfi
接下来我们分类讨论一些情况:
设
s
u
m
i
=
∑
k
=
1
i
t
i
sum_i=\sum\limits_{k=1}^it_i
sumi=k=1∑iti ,则前
i
i
i 个任务花费的最少时间为
s
u
m
i
sum_i
sumi ,最长时间为
s
u
m
i
+
i
sum_i+i
sumi+i
- s u m i > T sum_i>T sumi>T 时,说明不可能完成,应在此时 b r e a k break break
- s u m i + i ≤ T sum_i+i \le T sumi+i≤T ,说明此时一定能完成,此时有 f i = 1 f_i=1 fi=1
-
s
u
m
i
≤
T
<
s
u
m
i
+
i
sum_i \le T < sum_i+i
sumi≤T<sumi+i ,此时至多有
T
−
s
u
m
i
T-sum_i
T−sumi 个任务多花费了
1
1
1 分钟,因为我们枚举
1
1
1 到
T
−
s
u
m
i
T-sum_i
T−sumi 用组合数就能统计出所有可能的方案数,而总方案数为
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=2i∑k=0T−sumiCik
所以有:
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=1∑n2i∑k=0T−sumiCik
每次计算
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+1m−1=Cnm−2+Cnm−1Cn+1m=Cnm−1+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=0∑mCn+1k=2k=0∑mCnk−Cnm
因为
T
−
s
u
m
i
T−sum_i
T−sumi 是单调递减的,我们可以直接用上述公式又上一层转移到下一层
具体细节见代码:
#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;
}