仓鼠找sugar II

来源:互联网 发布:矩阵计算 袁亚湘 pdf 编辑:程序博客网 时间:2024/04/27 23:35

题目描述

小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a,是任意的)他的基友卧室(b,还是任意的)。(注意,a有可能等于b。)然而小仓鼠学OI学傻了,不知道怎么怎么样才能最短的走到目的地。于是他只能随便乱走。当他在每一个节点时,等概率到这个点的母亲或者所有孩子节点(例如这个节点有一个母亲节点和两个子节点,那么下一步走到这3个节点的概率都是1/3)。一但走到了他基友的卧室,就会停下。

现在小仓鼠希望知道,他走到目的地时,走的步数的期望。这个期望本来是一个有理数,但是为了避免误差,我们要求对这个有理数取模,%998244353。

下面是“分数”模运算的定义:

b, m互质

k = a/b (mod m) <=> kb = a (mod m)

这里求 x = 1/17 (mod 2668)

<=>
17x = 1 (mod 2668)
<=>
17x = 2668k + 1 (k∈整数)
取合适的k使得17|(2668k+1) 这里刚好17 | (2668 + 1)

所以k = 1, x = (2668+1)/17 = 157

当然,当k = 1 + 17n 时,

x = (2668 + 17·n·2668 + 1)/17 = 157 + 2668n

也符合条件(n任意整数)

但如果限定 2668 > x > 0,x是唯一的。

小仓鼠那么弱,还要天天被JOHNKRAM大爷虐,请你快来救救他吧!

输入输出格式

输入格式:
第一行一个正整数n,表示这棵树节点的个数。

接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。

输出格式:
一个整数,表示取模后的答案。

输入输出样例

输入样例#1:
3
1 2
1 3
输出样例#1:
110916041
说明

对于30%的数据 n<=5;

对于50%的数据 n<=5000;

对于所有数据 n<=100000。

样例解释

期望是16/9

如果a在叶子 b在根,E1=1。有2种情况。

如果a在根,b在叶子。E2=1/2+3*1/4+5*1/8…=3。有2种情况。

如果a和b都在不同的叶子,E3=E2+1。有2种情况。

如果a=b,E4=0,有3种情况。

所以期望是16/9,有理数取模后就是输出。

设f[u->v]表示u、v之间有边的情况下,从u到v的期望距离。考虑从u出发第一步走到哪里可以列出方程f[u->v]=1/d[u]+sum{(1+f[k->u]+f[u->v])/d[u]}(u、k之间有边且k!=v),d[u]表示u的度数。解方程得f[u->v]=d[u]+sum{f[k->u]}(u、k之间有边且k!=v)。把f[k->u]一层层代入,可得f[u->v]=sum{d[i]}(i在以v为根时u的子树内)。考虑每条边被计算了多少次,化简得f[u->v]=2siz[v][u]-1,siz[v][u]表示以v为根时u的子树大小。只需要计算出所有的siz[1][i],那么判断一下u和v谁是父亲就可以O(1)的计算出siz[v][u],进而计算出f[u->v]。

接下来考虑如何计算答案。因为期望的线性性,路径长度的期望等于每条边长度期望的和,所以考虑每条边在多少条路径中出现过,即可得出一条有向边u->v对答案的贡献是siz[v][u]*siz[u][v]*f[u->v]/n/n。对每条边各计算一次即可,时间复杂度O(n)。

const p=998244353;vartot,i,u,v:longint;n:int64;head,ret,next,size,w,ans,f,g:array[0..200022] of int64;procedure ins(u,v:longint);begin  tot:=tot+1;  ret[tot]:=v;  next[tot]:=head[u];  head[u]:=tot;end;function gpow(x,k:int64):int64;vart:int64;begin  t:=1;  while k>0 do  begin    if k and 1=1 then t:=t*x mod p;    x:=x*x mod p;    k:=k >> 1;  end;  exit(t);end;procedure dfs(u,pre:longint);vari,v:longint;begin  i:=head[u];  size[u]:=1;  while i<>0 do  begin    v:=ret[i];    if v<>pre then    begin      dfs(v,u);      w[i xor 1]:=2*size[v]-1;      w[i]:=2*n-2-w[i xor 1];      size[u]:=size[u]+size[v];    end;    i:=next[i];  end;  i:=head[u];  while i<>0 do  begin    v:=ret[i];    if v<>pre then    begin      f[u]:=(f[u]+f[v]+(size[v])*w[i xor 1]) mod p;      g[u]:=(g[u]+g[v]+(size[v])*w[i]) mod p;      ans[u]:=(ans[u]+g[v]*(size[u]-size[v]) mod p+(size[v])*(size[u]-size[v])*w[i] mod p+(size[v])*(size[u]-size[v])*w[i xor 1] mod p+f[v]*(size[u]-size[v]) mod p+ans[v]) mod p;    end;    i:=next[i];  end;end;begin  tot:=1;  readln(n);  for i:=1 to n-1 do  begin    readln(u,v);    ins(u,v);    ins(v,u);  end;  dfs(1,-1);  write(gpow(n*n mod p,p-2)*ans[1] mod p);end.
1 0
原创粉丝点击