【Goodbye Dingyou】【UOJ 351】新年的葉子

Description

UOJ原題鏈接
給定一棵樹,每次會隨機選擇一個葉子染黑,葉子可以被重複染黑,求期望多少次之後樹的直徑發生變化(只有白點參與直徑計算)
n<=5e5

Analysis

思路順序:
既然是直徑肯定會想到取出直徑中點,並根據一些轉化將問題變成如下模型:給定若干個集合,每次隨機染黑一個點(可能重複染黑),求期望多少次之後白點全部都在同一個集合中。
和獵人殺那題相反,由於重複染黑不好計算操作步數,我們轉化一下,變成不能重複染。假設總共有m個點,已經染黑了n個點,那麼染黑第n+1個點的期望步數就是m/(m-n)
我們只需要對於每種可能的染色序列,算出它的概率,乘上相應的步數就可以計算答案。可以通過枚舉最後剩下哪個集合,這個集合剩下多少點是白的,然後簡單數學推導計算了。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,b,a) for(int i=b;i>=a;--i)
#define efo(i,v,u) for(int i=BB[v],u=B[BB[v]][1];i;i=B[i][0],u=B[i][1])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
char ch;
int read(){int n=0,p=1;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';return n*p;}
const int N=5e5+5,mo=998244353;
int n,m,tot,BB[N],B[N<<1][2],B0;
void link(int u,int v){B[++B0][1]=v,B[B0][0]=BB[u],BB[u]=B0;}
ll ans,inv[N],fac[N],invfac[N];
ll qmi(ll x,ll n)
{
	ll t=1;
	for(;n;n>>=1,x=x*x%mo) if(n&1) t=t*x%mo;
	return t;
}
ll C(ll m,ll n){return (n<0 || n>m)?0:fac[m]*invfac[n]%mo*invfac[m-n]%mo;}
int num,len,rt,S,T,b[N];
void dfs1(int v=1,int fr=1,int d=1)
{
	if(d>len) len=d,S=v;int cnt=0;
	efo(i,v,u) if(u!=fr) dfs1(u,v,d+1),++cnt;
	if(cnt==0 || (v==1 && cnt==1)) m++;
}
int mx,stk[N],t1,t2;
void dfs2(int v=S,int fr=S,int d=1)
{
	stk[d]=v;
	if(d>len) len=d,T=v,rt=stk[d/2+1];
	efo(i,v,u) if(u!=fr) dfs2(u,v,d+1);
}
void dfs3(int v,int fr,int d=1)
{
	if(d==mx) t1++;
	if(d==mx-1) t2++;
	efo(i,v,u) if(u!=fr) dfs3(u,v,d+1);
}
int main()
{
	n=read();
	fac[0]=invfac[0]=1;
	fo(i,1,n) fac[i]=fac[i-1]*i%mo;
	invfac[n]=qmi(fac[n],mo-2);
	fd(i,n-1,1) invfac[i]=invfac[i+1]*(i+1)%mo;
	inv[1]=1;
	fo(i,2,n) inv[i]=(mo-mo/i)*inv[mo%i]%mo;
	int x,y;
	fo(i,1,n-1) x=read(),y=read(),link(x,y),link(y,x);
	dfs1();len=0;dfs2();
	fo(i,1,n) inv[i]=inv[i]*m%mo;
	mx=(len+1)/2;if(len&1) mx--;
	efo(i,rt,x)
	{
		t1=t2=0;dfs3(x,rt);
		if(len&1)
		{
			if(t1) b[++tot]=t1;
		}
		else
		if(t1) b[1]+=t1;else b[tot=2]+=t2;
	}
	fo(i,1,tot) num+=b[i];
	inv[num+1]=0;
	fd(i,num,1) inv[i]=(inv[i]+inv[i+1])%mo;
	fo(id,1,tot)
		for(int i=1,k=b[id];i<=b[id];i++)
		{
			ll t=fac[i]*C(k,i)%mo*(num-k)%mo*fac[num-i-1]%mo*inv[i+1]%mo;
			ans=(ans+t)%mo;
		}
	printf("%lld",ans*invfac[num]%mo);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章