Hello my friend

Description

给出一棵黑白树,你现在在一号节点。
你现在有一个计数器,初始为0,每个时刻你需要进行如下操作
1:如果你所在的点为第一次到达或者为黑点则计数器+1
2:等概率的走到和你所在的点相邻的点
3:如果你所在的点度数为1则停止
保证1号点的度数>1,求最后计数器的数值的期望。
n<=1e5

Solution

概率期望和我讲不来.jpg
显然黑点白点可以独立考虑,先考虑黑点怎么做
设F[i]表示在i点的期望,其中叶子结点的F为1
那么 F[i]=1+1deg[i]F[j]
我们可以考虑把F[i]表示成k*F[fa[i]]+b的形式,那么b[1]就是答案。

再来考虑白点,根据期望的线性性我们可以单独考虑每一个白点被经过的概率。
也就是每个点被经过的概率,设F[i]表示从i走到fa[i]的概率,G[i]表示从fa[i]走到i的概率
式子随便写写就好了。
那么把这两个做法结合起来就是满分。

被wdc吊起来打

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
using namespace std;

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

typedef long long ll;

const int N=1e5+5,Mo=998244353;

int pwr(int x,int y) {
    int z=1;
    for(;y;y>>=1,x=(ll)x*x%Mo)
        if (y&1) z=(ll)z*x%Mo;
    return z;
}

int t[N<<1],nxt[N<<1],lst[N],l;
void add(int x,int y) {
    t[++l]=y;nxt[l]=lst[x];lst[x]=l;
}

int n,x,y,f[N],g[N],deg[N],col[N],kk[N],bb[N],Dp[N],sum[N],ans;

void dfs(int x,int y) {
    if (deg[x]==1) {
        kk[x]=f[x]=0;
        bb[x]=col[x];
        return;
    }
    rep(i,x) if (t[i]!=y) dfs(t[i],x);
    int k=1,d=pwr(deg[x],Mo-2),b=col[x],r=1;
    rep(i,x)
        if (t[i]!=y) {
            (k+=Mo-(ll)kk[t[i]]*d%Mo)%=Mo;
            (b+=(ll)bb[t[i]]*d%Mo)%=Mo;
            (r+=Mo-(ll)f[t[i]]*d%Mo)%=Mo;
        }
    kk[x]=(ll)d*pwr(k,Mo-2)%Mo;
    bb[x]=(ll)b*pwr(k,Mo-2)%Mo;
    f[x]=(ll)pwr((ll)r*deg[x]%Mo,Mo-2);
}

void dp(int x,int y) {
    if (y) {
        int r=pwr(deg[y],Mo-2);
        int d=1+Mo-(ll)g[y]*r%Mo;
        (d+=Mo-(ll)sum[y]*r%Mo)%=Mo;
        (d+=(ll)f[x]*r%Mo)%=Mo;
        g[x]=pwr((ll)deg[y]*d%Mo,Mo-2);
    }
    rep(i,x) if (t[i]!=y) (sum[x]+=f[t[i]])%=Mo;
    rep(i,x) if (t[i]!=y) dp(t[i],x);
}

void calc(int x,int y) {
    if (!col[x]) (ans+=Dp[x])%=Mo;
    int sum=0;
    rep(i,x)
        if (t[i]!=y) {
            Dp[t[i]]=(ll)Dp[x]*g[t[i]]%Mo;
            calc(t[i],x);
        }
}

int main() {
    freopen("sad.in","r",stdin);
    freopen("sad.out","w",stdout);
    n=read();
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    fo(i,1,n) {
        col[i]=ch-'0';
        ch=getchar();
    }
    fo(i,1,n-1) {
        x=read();y=read();
        add(x,y);add(y,x);
        deg[x]++;deg[y]++;
    }
    dfs(1,0);
    ans=bb[1];dp(1,0);
    Dp[1]=1;calc(1,0);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值