牛客 Valuable Forest(XJOJ4 F森林)

Description

一棵树的 F 值是所有点的度数的平方和,

一个森林的 F 值是森林里所有树的 F 值的和。

求所有 n 个点的森林的 F 值的和 (有标号,树都是无根树)。

Solution

prufer序列:n个点的无根树共有$n^{n-2}$种
令$f(n)$为有n个点的森林的个数
$$f(n)=\sum_{i=0}^{n-1} C_{n-1}^i f(n-i-1)(i+1)^{i-1}$$
意思是加入第n个点时,在原来的n-1个点中选择i个点与其连成一棵树
令$A(n)$为n个点的所有无根树中的权值之和
$$A(n)=n \sum_{d=1}^{n-1}d^2 C_{n-2}^{d-1} (n-1)^{n-d-1}$$
意思是对于每一个点枚举度数d,统计其在prufer序列中仅出现d-1次的方案数
令$F(n)$记录答案
$$F(n)=\sum_{i=0}^{n-1} C_{n-1}^{i} [(i+1)^{i-1}F(n-i-1)+f(n-i-1)A(i+1)]$$
意思是在加入第n个点时,在原来的n-1个点中选择i个点与其形成一棵树,答案为这样的树的总个数乘对应的权值和 + 其余的n-i-1个点形成森林的个数乘方案数

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
using namespace std;
long long C[5005][5005],T,mod,A[5005],F[5005],f[5005],st[5005],n,qp[5005][5005];
inline long long read()
{
    long long f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
long long ksm(long long a,long long p)
{
    long long ret=1ll;
    while(p)
    {
        if(p&1)
        {
            (ret*=a)%=mod;
        }
        (a*=a)%=mod;
        p>>=1;
    }
    return ret;
}
int main()
{
    T=read(),mod=read();
    for(int i=1;i<=5000;i++)
    {
        qp[i][0]=1ll;
        for(int j=1;j<=5000;j++)
        {
            qp[i][j]=qp[i][j-1]*i%mod;
        }
    }
    C[0][0]=1ll;
    for(long long i=1;i<=5000;i++)
    {
        C[i][0]=1ll;
        for(long long j=1;j<=i;j++)
        {
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
    }
    st[0]=st[1]=1ll;
    for(int i=2;i<=5000;i++)
    {
        st[i]=ksm(i,i-2);
    }
    f[0]=f[1]=1ll;
    for(long long i=2;i<=5000;i++)
    {
        for(long long j=0;j<=i-1;j++)
        {
            (f[i]+=C[i-1][j]*f[i-1-j]%mod*st[j+1]%mod)%=mod;
        }
    }
    for(long long i=2;i<=5000;i++)
    {
        for(long long d=1;d<=i-1;d++)
        {
            (A[i]+=d*d%mod*C[i-2][d-1]%mod*qp[i-1][i-2-d+1]%mod)%=mod;
        }
        (A[i]*=i)%=mod;
    }
    for(long long i=2;i<=5000;i++)
    {
        for(long long j=0;j<=i-1;j++)
        {
            (F[i]+=C[i-1][j]*(st[j+1]*F[i-1-j]%mod+f[i-j-1]*A[j+1]%mod)%mod)%=mod;
        }
    }
    for(;T;T--)
    {
        n=read();
        printf("%lld\n",F[n]);
    }
    return 0;
}
Valuable Forest

 

posted @ 2020-08-03 14:00  QDK_Storm  阅读(195)  评论(0编辑  收藏  举报