2021陕西省赛 D.Disease(树形dp&期望dp)
因为是求最小等级的期望,因此不需要往下考虑。
先树形dp计算每个结点不被感染的概率。
然后利用差分的思想。
对于答案为第层的贡献就是前
层没被感染的概率减取前
层没被感染的概率。
前层没被感染的概率就是前
都没被大自然感染,且第
层的所有结点不被感染。
代码
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int N=2e5+50;
const ll mod=1e9+7;
ll fpow(ll x,ll k){
ll ans=1;x=(x+mod)%mod;
while(k){
if(k&1) ans*=x,ans%=mod;
x*=x;x%=mod;
k>>=1;
}
return ans%mod;
}
ll divd(ll a,ll b){
return (a%mod)*(fpow(b,mod-2)%mod)%mod;
}
struct edge{
int u,v;
ll p;
edge(int x,int y,ll a):u(x),v(y),p(a){}
edge(){}
}e[N<<1];
int front[N],nxt[N<<1],en,n,dep=0;
ll pt[N],dp[N],d[N];
inline void add(int u,int v,ll p){
e[++en].u=u;e[en].v=v;e[en].p=p;
nxt[en]=front[u];front[u]=en;
}
void dfs(int p,int fa){
ll ans=1-pt[p]+mod;ans%=mod;
for(int eg=front[p];eg;eg=nxt[eg]){
if(e[eg].v!=fa){
dfs(e[eg].v,p);
ans*=(dp[e[eg].v]+((1-dp[e[eg].v]+mod)%mod*((1-e[eg].p+mod)%mod)%mod))%mod;
ans%=mod;
}
}
dp[p]=ans;
return ;
}
ll sum[N],s[N];
void dfs1(int p,int fa,int depth){
dep=max(dep,depth);
d[depth]=d[depth]*dp[p]%mod;
s[depth]=s[depth]*((1-pt[p]+mod)%mod)%mod;
for(int eg=front[p];eg;eg=nxt[eg])
if(e[eg].v!=fa) dfs1(e[eg].v,p,depth+1);
}
int main(){
int x,y;
ll a,b,ans;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld%lld",&a,&b),pt[i]=divd(a,b);
for(int i=1;i<n;++i){
scanf("%d%d%lld%lld",&x,&y,&a,&b);
add(x,y,divd(a,b));add(y,x,divd(a,b));
}
dfs(1,1);
for(int i=1;i<=n;++i) s[i]=d[i]=1;
dfs1(1,1,1);
sum[0]=1;
for(int i=1;i<=n;++i) sum[i]=s[i]*sum[i-1]%mod;
ans=1-dp[1]+mod;ans%=mod;
for(int i=2;i<=dep;++i){
ll dx=i;
// 前i-1层: sum[i-2]*d[i-1]
//前i层: sum[i-1]*d[i]=sum[i-1]*s[i]*d[i]
ans+=dx*sum[i-2]%mod*((d[i-1]-s[i-1]*d[i]%mod+mod)%mod)%mod;
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}