【UOJ 351】新年的葉子
阿新 • • 發佈:2019-01-04
Description
對於一棵樹,每次隨機染黑一個葉子(可能會重複染黑),期望多少次後直徑變小?.
Solution
其實這題正確的題意應該是:對於每種直徑與原圖不同的染色方案,在第多少步時直徑變小,求期望嗎,
也就是:我們會不停的染色下去,每種方案的權值為它直徑第一次變小的時候。
先考慮直徑R為偶數的情況:
這種情況下,顯然可以找到一個點root,使得所有的直徑都經過它,以這個點為根給每個點定深度
那麼,只有
把所有
直徑改變了,當且僅當只剩下一個集合的點沒有被刪完,
對於R為單數的情況:
顯然有必經邊,那麼就以這條邊切開兩半,也就是隻有兩個集合,集合中的點為
有一個值是可以先預處理的:可以推出,當全域性還剩x個點時,再刪掉一個沒被刪的點的代價為
對於無關點,我們可以視作,這些點已經被刪掉了,也就是一開始就已經刪掉m1個點,
那麼現在問題就轉化成:每次刪掉一個沒有刪掉的點(帶權),求刪剩一個集合的期望,
這個可以用(所有方案代價總和)/(方案數)的方法算概率,
列舉一個集合(大小為d),假設最後剩下它,其他的集合全選完,再列舉這個集合最後選了i個,貢獻為:(d0為所有集合大小)
(注意:要保證最後一個選的一定不是當前集合的點,要不會算重)
因為無限次的染色一定會全部染上黑色,後邊的(d-i)!表示剩下的亂選,d0!表示全部的方案。
期望=權值*概率,
複雜度:
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define max(q,w) ((q)>(w)?(q):(w))
using namespace std;
typedef long long LL;
const int N=500500,mo=998244353;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
LL ans;
int B[2*N][2],A[N],Bv[N],B0;
int dp[N];
int root,zx1,root1;
LL jc[N],jcn[N],sum[N];
int d[N],lf;
void link(int q,int w)
{
++Bv[q],++Bv[w];
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q;
}
void dfsf(int q,int fa)
{
dp[q]=0;
efo(i,q)if(B[i][1]!=fa)dfsf(B[i][1],q),dp[q]=max(dp[q],dp[B[i][1]]+1);
if(1==Bv[q])++lf;
}
void dfs(int q,int mx,int fa)
{
int mx1=0,t=0;
efo(i,q)if(B[i][1]!=fa)
{
if(dp[B[i][1]]+1>mx)t=mx,mx=dp[B[i][1]]+1,mx1=B[i][1];
else if(dp[B[i][1]]+1>t)t=dp[B[i][1]]+1;
}
ans=max(ans,mx+t);
if(zx1>mx)zx1=mx,root=q;
else if(zx1==mx)root1=q;
efo(i,q)if(B[i][1]!=fa)dfs(B[i][1],(mx1==B[i][1]?t:mx)+1,q);
}
int dfss(int q,int c,int fa)
{
int ans=(!c);
efo(i,q)if(B[i][1]!=fa)ans+=dfss(B[i][1],c-1,q);
return ans;
}
LL ksm(LL q,int w)
{
LL ans=1;
for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
return ans;
}
LL C(int m,int n){return jc[m]*jcn[m-n]%mo*jcn[n]%mo;}
LL Gans(LL m,LL m1)
{
fod(i,m,0)sum[i]=(sum[i+1]+m1*ksm(i,mo-2))%mo;
LL ans=0,ans1=0;
fo(I,1,d[0])
{
fo(i,0,d[I]-1)
{
LL t=C(d[I],i)*jc[m-d[I]+i-1]%mo*(m-d[I])%mo;
ans=(ans+t*sum[d[I]-i+1]%mo*jc[d[I]-i])%mo;
ans1=(ans1+t)%mo;
}
}
return ans*jcn[m]%mo;
}
int main()
{
int q,w;
read(n);
fo(i,1,n-1)read(q),read(w),link(q,w);
jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*(LL)i%mo;
jcn[n]=ksm(jc[n],mo-2);fod(i,n-1,0)jcn[i]=jcn[i+1]*(i+1LL)%mo;
dfsf(1,0);
zx1=1e9;dfs(1,0,0);
if(ans&1)
{
d[0]=2;
d[1]=dfss(root,ans/2,root1);
d[2]=dfss(root1,ans/2,root);
ans=Gans(d[1]+d[2],lf);
}else
{
q=0;d[0]=0;
efo(i,root)q+=(d[++d[0]]=dfss(B[i][1],ans/2-1,root));
ans=Gans(q,lf);
}
printf("%lld\n",ans);
return 0;
}