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为所有集合大小)
(注意:要保证最后一个选的一定不是当前集合的点,要不会算重)
因为无限次的染色一定会全部染上黑色,后边的(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;
}