zoukankan      html  css  js  c++  java
  • Valuable Forests【prufer序列】

    题意

    定义一棵无根树 (T) 的价值为:(sum_{uin V(T)}{(d(u))^2}),其中 (V(T))(T) 的所有点组成的点集,(d(u)) 是点 (u) 的度。定义森林的价值为所有由它生成的树的价值之和。现在,让你求出由 (N) 个编号的点组成的所有森林的价值之和,结果对 (M) 取模。

    (1leq T leq 5000,1leq M leq 2^{30} 且为素数,1leq N leq 5000)

    题目链接:https://ac.nowcoder.com/acm/contest/5672/I

    分析

    本需要用到 ( ext{prufer}) 序列的有关性质。

    定义如下数组:

    (f(n))(n) 个点的森林个数

    (st(n))(n) 个点的完全图,可以构成 (n^{n-2}) 个不同的树(根据序列的性质)

    在第 (n) 个点加入时,可以选择 (i) 个点与它组成一棵树,有:

    [f(n)=sum_{i=0}^{n-1}{C_{n-1}^{i}·st(i+1)·f(n-i-1)} ]

    (n) 个点能形成的所有无根树的权值和为 (A_n)

    枚举每一个点 (i),再枚举这个点的度数 (j)。第 (i) 个点的度数为 (j) 的贡献 (=) (j^2) 与序列中有且仅有 (j-1)(i) 的方案数之积。

    [A(n)=sum_{i=1}^{n}{sum_{j=1}^{n-1}{j^2·C_{n-2}^{j-1}(n-1)^{n-j-1}}} ]

    (i) 省略,可得:

    [A(n)=nsum_{j=1}^{n-1}{j^2·C_{n-2}^{j-1}(n-1)^{n-j-1}} ]

    最后,假设 (n) 个点的形成的森林的权值和为 (F_n),类似求 (f_n) 的方法,将第 (n) 个点加入时,选择 (i) 个点和它构成一棵树,可得:

    [F(n)=sum_{i=0}^{n-1}{C_{n-1}^{i}(st(i+1)·F(n-i-1)+f(n-i-1)·A(i+1))} ]

    选择 (i) 个点和第 (n) 个点形成一个有 (i+1) 个点的树,与之相对应,其他的点能形成 (f(n-i-1)) 种森林,对于每一种形成方式,都能得到 (A(i+1)) 的权值贡献,因此他们需要相乘,前面的式子同理。

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int N=5050;
    int f[N],F[N],A[N],st[N],c[N][N];
    int M;
    ll power(ll a,ll b)
    {
        ll res=1;
        a%=M;
        while(b)
        {
            if(b&1) res=res*a%M;
            a=a*a%M;
            b>>=1;
        }
        return res;
    }
    void init()
    {
        int maxn=5000;
        for(int i=0;i<=maxn;i++)
        {
            c[i][0]=c[i][i]=1;
            for(int j=1;j<i;j++)
                c[i][j]=(c[i-1][j-1]+c[i-1][j])%M;
        }
        st[0]=st[1]=1;
        for(int i=2;i<=maxn;i++)
            st[i]=power(i,i-2);
        f[0]=f[1]=1;
        for(int i=2;i<=maxn;i++)
        {
            for(int j=0;j<i;j++)
                f[i]=(f[i]+1LL*c[i-1][j]*st[j+1]%M*f[i-j-1]%M)%M;
        }
        A[1]=0;
        for(int i=2;i<=maxn;i++)
        {
            int res=0;
            int inv=power(i-1,M-2);
            int tp=power(i-1,i-1);
            for(int j=1;j<i;j++)
            {
                tp=1LL*tp*inv%M;
                res=(res+1LL*j*j%M*c[i-2][j-1]%M*tp%M)%M;
            }
            A[i]=1LL*i*res%M;
        }
        for(int i=1;i<=maxn;i++)
        {
            F[i]=0;
            for(int j=0;j<i;j++)
                F[i]=(F[i]+1LL*c[i-1][j]*(1LL*st[j+1]*F[i-j-1]%M+1LL*f[i-j-1]*A[j+1]%M)%M)%M;
        }
    }
    int main()
    {
        int T,n;
        scanf("%d%d",&T,&M);
        init();
        while(T--)
        {
            scanf("%d",&n);
            printf("%d
    ",F[n]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    简单的几句接口调用,完美完成缩短网站
    nodejs语言实现验证码生成功能
    人工智能:文本相似度分析
    SolrCloud 5.2.1 installation and configuration
    借鉴DP思想: HouseRobberIII
    有意思的数学题:Trapping Rain Water
    API认证方法一览
    FE: Responsive Web Design Overview
    FE: Sass and Bootstrap 3 with Sass
    假期小记:14年寒假二三四事(儿)
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13625017.html
Copyright © 2011-2022 走看看