zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第七场)I-Valuable Forests prufer序列

    I-Valuable Forests

    题意

    定义一个森林的权值为这个森林所有点的度数和,计算所有(n)个点的森林的权值和。

    分析

    首先我们需要学习一下 prufer 序列,得到一个公式:

    一个 (n) 个点 (m) 条边的带标号无向图有 (k) 个连通块。第 (i) 个连通块的大小为 (s_i) 。添加 (k-1) 条边使得整个图连通的方案数为

    [n^{k-2} cdot prod_{i=1}^{s_i} ]

    定义(a[n])(n)个点的带标号的树的个数,由上述公式可知

    [a_i=i^{i-2} ]

    定义(b[n])(n)个点的带标号的森林的个数,递推求出(b[n])

    首先(b_i)包含(a_i),考虑向图中加入点(i)(j)个点连成一颗(j+1)个点的树的方案数为(a_{j+1}),剩余(i-j-1)个点自成森林的方案数为(b_{i-j-1}),合起来就是(a_{j+1} cdot b_{i-j-1})

    [b_i=a_i+sum_{j=0}^{i-2}inom{i-1}{j} cdot a_{j+1} cdot b_{i-j-1} ]

    定义(c[n])为所有(n)个点的带标号的树的权值和,考虑(i)个点的树中点(i)直接和(j)个点相连,剩余(i-j-1)个点通过这(j)个点间接和点(i)相连的方案数为(D),贡献为(j^2 cdot D),显然我们是要连接(i-1)个连通块,其中一个连通块大小为(j)(i-2)个连通块的大小为(1)(D=(i-1)^{i-j-2}cdot j)。点(i)直接和剩余(i-1)个点相连的答案要单独算,有(i)个点,将总贡献再乘个(i)

    [c_i=icdot ((i-1)^2+ sum_{j=1}^{i-2}inom{i-1}{j}cdot j^3cdot (i-1)^{i-j-2}) ]

    定义(d[n])为所有(n)个点的带标号的森林的权值和,递推求出(d[n])

    首先(d_i)包含(c_i),和之前类似,考虑有(j)个点和(i)号点相连,那么这个森林是由一个(j+1)个点的树和(i-j-1)个点的森林组成,那这部分的贡献就是 树的贡献乘上森林的方案数+森林的贡献乘上树的方案数 。

    [d_i=c_i+sum_{j=0}^{i-2}inom{i-1}{j}cdot (c_{j+1}cdot b_{i-j-1}+d_{i-j-1}cdot a_{j+1}) ]

    Code

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<sstream>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<bitset>
    #include<queue>
    #include<cmath>
    #include<stack>
    #include<set>
    #include<map>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int N=1e5+10;
    const int inf=1e9;
    int T,p;
    ll a[5010],b[5010],c[5010],d[5010],f[5010][5010],C[5010][5010];
    void init(int n){
        rep(i,1,n){
            f[i][0]=1;
            rep(j,1,n) f[i][j]=f[i][j-1]*i%p;
        }
        C[0][0]=1;
        rep(i,1,n){
            C[i][0]=1;
            rep(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
        }
        a[1]=1;
        rep(i,2,n) a[i]=f[i][i-2];
        rep(i,1,n){
            b[i]=a[i];
            rep(j,0,i-2) b[i]=(b[i]+a[j+1]*b[i-j-1]%p*C[i-1][j]%p)%p;
        }
        rep(i,1,n){
            c[i]=(i-1)*(i-1)%p;
            rep(j,1,i-2) c[i]=(c[i]+1ll*j*j*j%p*f[i-1][i-j-2]%p*C[i-1][j]%p)%p;
            c[i]=i*c[i]%p;
        }
        rep(i,1,n){
            d[i]=c[i];
            rep(j,0,i-2) d[i]=(d[i]+(c[j+1]*b[i-j-1]%p+a[j+1]*d[i-j-1]%p)%p*C[i-1][j]%p)%p;
        }
    }
    int main(){
        //ios::sync_with_stdio(false);
        //freopen("in","r",stdin);
        scanf("%d%d",&T,&p);
        init(5000);
        while(T--){
            int n;
            scanf("%d",&n);
            printf("%lld
    ",d[n]);
        }
        return 0;
    }
    
  • 相关阅读:
    Android使用文件存储数据
    Android Sudoku第一版
    Android Preference
    Android Sudoku应用挂掉的问题
    Android刷新Dialog
    Android应用增加计时器
    使用Jquery的Ajax实现无刷新更新,修改,删除页面
    鼠标划过用户名时在鼠标右下角显示div展示用户资料
    网页宽高自适应大小
    学会读JQuery等JS插件源码
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13492646.html
Copyright © 2011-2022 走看看