1. 程式人生 > >【UOJ 351】新年的葉子

【UOJ 351】新年的葉子

Description

對於一棵樹,每次隨機染黑一個葉子(可能會重複染黑),期望多少次後直徑變小?.

Solution

其實這題正確的題意應該是:對於每種直徑與原圖不同的染色方案,在第多少步時直徑變小,求期望嗎,
也就是:我們會不停的染色下去,每種方案的權值為它直徑第一次變小的時候。

先考慮直徑R為偶數的情況:
這種情況下,顯然可以找到一個點root,使得所有的直徑都經過它,以這個點為根給每個點定深度dpx
那麼,只有dpx=R/2的點才有可能為直徑端點,剩下的dpx<R/2的葉子為無關點,先統計出來設有m1個,
把所有dpx=R/2的點按他是root的哪一棵子樹分成幾個集合,
直徑改變了,當且僅當只剩下一個集合的點沒有被刪完,

對於R為單數的情況:
顯然有必經邊,那麼就以這條邊切開兩半,也就是隻有兩個集合,集合中的點為dpx=R2,m1也一樣統計,這樣就和偶數的一樣了

有一個值是可以先預處理的:可以推出,當全域性還剩x個點時,再刪掉一個沒被刪的點的代價為mx,m為全部葉子數,
對於無關點,我們可以視作,這些點已經被刪掉了,也就是一開始就已經刪掉m1個點,

那麼現在問題就轉化成:每次刪掉一個沒有刪掉的點(帶權),求刪剩一個集合的期望,
這個可以用(所有方案代價總和)/(方案數)的方法算概率,

列舉一個集合(大小為d),假設最後剩下它,其他的集合全選完,再列舉這個集合最後選了i個,貢獻為:(d0為所有集合大小)

i=0d1Cid(d0d+i1)!(d0d)(j=di+1d0mj)(di)!1d0!
(注意:要保證最後一個選的一定不是當前集合的點,要不會算重)
因為無限次的染色一定會全部染上黑色,後邊的(d-i)!表示剩下的亂選,d0!表示全部的方案。

期望=權值*概率,

複雜度:O(nlog(n))(計算逆元要個log)

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; }