您的位置:首页 > 其它

JZOJ 5444. 【NOIP2017提高A组冲刺11.2】救赎

2017-11-07 21:39 375 查看

题目

对于一棵有根树的每一个非叶子节点,我们都等概率选中其一个儿子节点作为偏好儿子。对于一条从父亲指向儿子的树边(u,v),如果v是u的偏好儿子,则称这条边为重边,否则为轻边。

我们定义一棵有根树的权值为其每一个节点到根路径上的轻边条数的和的期望值。

请对无根树每一个节点输出其为根的有根树的权值。答案模998244353。

题解

题目条件

①每条边都有固定的概率选为重/轻边。

②求的是期望(其他点与根节点的轻边条数之和的期望)。

突破口

①求“和的期望”,就是要求“期望的和”(每条边对答案的贡献的期望)。(期望的线性性)

②每条边的……概率固定。

困惑点

求期望有时候可以这样求:先知道总的分母,再将对答案的贡献加起来作为分子。作为最后的期望。但是这道题如果要这样做,不能够O(1)换根,总时间复杂度为O(n2)。

具体做法

考虑期望就直接算每条边对答案的期望贡献就好了,不要想太多。

那么每条边对答案的贡献为:

Σ(size[x]−1)∗(d[x]−1)d[x]

对于每个经过x的点,乘上每条与x和son[x]连着的边的期望。

然后可以发现,当换根的时候,变的只是x的期望和son[x]的期望,重新算一下就好了。

总结

求期望就求每个点/边对答案的期望贡献,不要想太多。(特别强调)

一般地,求期望逆推,求概率顺推。求概率,一般让我们求这个:f[i]=Σ(f[j]∗p(i,j))

求期望,一般让我们求这个:E[i]=Σ((E[j]+k)∗p(i,j))

可见,若要知道i的期望,就要知道与i有边相连的所有j的期望,所以逆推。如果要知道j的概率,知道i的概率即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200010
#define LL long long
#define mo 998244353
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int to,next;
};note edge[N*2];
LL i,j,k,l,n,m,temp;
int tot,head
;
LL f
,h
,deg
;
int d
,fa
;
LL g
,siz
;
LL ny
;
LL ans
;
int y,u,v,v1,root;
int read(){
int fh=1,res=0;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
return res*fh;
}
void write(LL x){
if(x>9)write(x/10);
P(x%10+'0');
}
LL ksm(LL x,LL y){
LL res=1;
for(;y;y/=2,x=(x*x)%mo)
if(y&1)res=(res*x)%mo;
return res;
}
void lb(int x,int y){
edge[++tot].to=y;
deg[y]++;
edge[tot].next=head[x];
head[x]=tot;
}
void dg(int x){
siz[x]=1;
for(int i=head[x];i;i=edge[i].next)
if(fa[x]!=edge[i].to){
fa[edge[i].to]=x;
d[x]++;
dg(edge[i].to);
siz[x]+=siz[edge[i].to];
}
ans[1]=(ans[1]+(siz[x]-1)*(d[x]-1)%mo*ny[d[x]])%mo;
}
void calc(int x,int v){
ans[x]=v;
for(int i=head[x];i;i=edge[i].next)
if(fa[x]!=edge[i].to){
v1=v;
y=edge[i].to;
v1=(v1-(n-1)*(deg[x]-1)%mo*ny[deg[x]]+mo)%mo;
v1=(v1-(siz[y]-1)*(d[y]-1)%mo*ny[d[y]]%mo)%mo;
v1=(v1+(n-1)*(deg[y]-1)%mo*ny[deg[y]]+mo)%mo;
v1=(v1+(n-siz[y]-1)*(deg[x]-2)%mo*ny[deg[x]-1]%mo)%mo;
calc(y,v1);
}
}
int main(){
ny[0]=ny[1]=1;
fo(i,2,N-10)ny[i]=ksm(i,mo-2);
n=read();
fo(i,1,n-1){
u=read(),v=read();
lb(u,v);lb(v,u);
}
dg(1);
calc(1,ans[1]);
fo(i,1,n)write(ans[i]),P('\n');
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: