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

猜你喜欢

转载自blog.csdn.net/howarli/article/details/79336713