链接:https://ac.nowcoder.com/acm/contest/368/C
来源:牛客网
题目比较简单,但因为比较典型所以记录一下。
另外,这种题一定要分清事件的概率,否则容易全盘皆错。
这题中,某一天是否发生流星雨的概率,不仅和当天有关,还和之前的情况有关。假设这个事件发生的概率为
d
p
[
i
]
dp[i]
dp[i],则
d
p
[
i
]
=
d
p
[
i
−
1
]
∗
(
p
i
+
P
)
+
(
1
−
d
p
[
i
−
1
]
)
∗
p
i
=
P
∗
d
p
[
i
−
1
]
+
p
i
dp[i]=dp[i-1]*(p_i+P)+(1-dp[i-1])*p_i=P*dp[i-1]+p_i
dp[i]=dp[i−1]∗(pi+P)+(1−dp[i−1])∗pi=P∗dp[i−1]+pi,于是可以递推。
我后来又设了数组s来求出某一天是否发生流星雨的概率的条件下到这天的流星数期望,企图递推求出答案,可行,但是后来发现没有必要。因为数学期望具有可加性,无论两个事件是否独立,所以直接有
a
n
s
=
∑
d
p
[
i
]
∗
w
[
i
]
ans=\sum dp[i]*w[i]
ans=∑dp[i]∗w[i]
#include <cstdio>
#include <algorithm>
#define mo 1000000007
using namespace std;
using LL=long long;
struct frac //这里也可以不用定义frac类,直接用一个整数=分子*分母的逆元来表示分数,代码会短很多,而效率会稍微差一些
{
int x,y;
frac(int x=0, int y=0):x(x),y(y){}
frac(LL x, LL y):x(int(x)),y(int(y)){}
frac operator+(const frac &t) const
{
return (frac){((LL)x*t.y+(LL)t.x*y)%mo,(LL)y*t.y%mo};
}
frac operator-(const frac &t) const
{
return (frac){((LL)x*t.y-(LL)t.x*y%mo)%mo,(LL)y*t.y%mo};
}
frac operator*(const frac &t) const
{
return (frac){(LL)x*t.x%mo,(LL)y*t.y%mo};
}
frac operator/(const frac &t) const
{
return (frac){(LL)x*t.y%mo,(LL)y*t.x%mo};
}
}one(1,1),dp[100005],s[100005][2],w[100005],P,p[100005],ans;
int n;
int quick_power(int x, int y)
{
int res=1,base=x;
while(y)
{
if(y&1)
res=(LL)res*base%mo;
base=(LL)base*base%mo;
y>>=1;
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&P.x,&P.y);
for(int i=1;i<=n;i++)
scanf("%d",&w[i].x),w[i].y=1;
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
dp[1]=p[1];
for(int i=2;i<=n;i++)
dp[i]=P*dp[i-1]+p[i];
//s[1][0]=(frac){0,1};
//s[1][1]=w[1];
ans=(frac){0,1};
for(int i=1;i<=n;i++)
{
ans=ans+dp[i]*w[i];
//s[i][1]=w[i]+((s[i-1][1])*(p[i]+P)*dp[i-1]+(s[i-1][0])*p[i]*(one-dp[i-1]))/dp[i];原先的思路,s[i][1]表示第i步发生流星雨时的期望总数
//s[i][0]=(s[i-1][1]*(one-p[i]-P)*dp[i-1]+s[i-1][0]*(one-p[i])*(one-dp[i-1]))/(one-dp[i]);原先的思路,s[i][0]表示第i步不发生流星雨时的期望总数
}
//ans=s[n][1]*dp[n]+s[n][0]*(one-dp[n]);
printf("%lld",(LL)ans.x*quick_power(ans.y,mo-2)%mo);
return 0;
}