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

    dp+prufer 序列 2020牛客暑期多校训练营(第七场)Valuable Forests

    题目大意:

    题解:

    这个题目首先要知道无根树计数-prufer序列,学习来源 无根树的计数——prufer序列

    然后就是一点点思维+dp

    • 通过prufer序列可以知道,对于一个n大小的无根树,不同的树有 (n^{n-2}) (其实就是n-2个点,每个点都有n种可能)
    • 本题要求无根树所有点的度数的平方和,prufer的一个重要性质就是序列中某个编号出现的次数就是这个编号节点的度数-1,所以对于一个大小为n的树,有n-2个格子可以放数字进去,先枚举1的数量,求出1的权值,再枚举2的数量,求出2节点的权值,以此类推,可以求出大小是n可以构成的所有无根树的权值和。
    • 第二点求出了大小为n可以构成的所有无根树的权值之和,但是题目要求大小为n的所有森林的权值和。这个可以定一个 (res[i]) 表示大小为 (i) 的森林无根树的组成方案。
    • 假设每次放入的一个点一定是新的一棵树,所以枚举每次放入一个点可以构成的树的大小。
    • 转移方程:$res[i] += res[i-j]C_{i-1}^{j-1}j^{j-2} $
    #include <bits/stdc++.h>
    #define debug(x) cout<<"debug:"<<#x<<" = "<<x<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn = 5e3+10;
    ll dp[maxn],res[maxn],c[maxn][maxn],f[maxn];
    
    int main() {
        int T, mod;
        scanf("%d%d", &T, &mod);
        for (int i = 0; i < maxn; i++) {
            c[i][0] = 1;
            for (int j = 1; j < maxn; j++) {
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
            }
        }
        for (int i = 2; i < maxn; i++) {
            ll pre = 1;
            for (int j = i - 2; j >= 0; j--) {
                dp[i] = (dp[i] + c[i - 2][j] * pre % mod * (j + 1) % mod * (j + 1) % mod) % mod;
                pre = pre * (i - 1) % mod;
            }
            dp[i] = dp[i] * i % mod;
        }
        for (int i = 0; i < maxn; i++) {
            f[i] = 1;
            for (int j = i - 2; j >= 1; j--)f[i] = f[i] * i % mod;
        }
        res[0] = 1,res[1] = 1;
        for (int i = 2; i < maxn; i++) {
            for (int j = i; j >= 1; j--) {
                res[i] = (res[i] + res[i - j] * c[i - 1][j - 1] % mod * f[j]%mod)%mod;
            }
    //        printf("res[%d]=%lld
    ",i,res[i]);
        }
        while(T--){
            int n;
            scanf("%d",&n);
            ll ans = 0;
            for(int i = 2;i<=n;i++) {
            	ans = (ans + c[n][i] * res[n - i] % mod * dp[i] % mod)%mod;
    //        	printf("c[%d][%d]=%lld res[%d]=%lld dp[%d]=%lld
    ",n,i,c[n][i],n-i,res[n-i],i,dp[i]);
            }
            printf("%lld
    ",ans);
        }
    }
    
  • 相关阅读:
    shell安装kettle
    shell安装jdk
    shell脚本之系统初始化设置(设置selinux、设置ulimit、设置firewalld、设置time_zone)
    关闭防火墙
    todo的使用
    Android Dagger2.0 学习一下
    Android零碎知识点
    windows7 服务中上找不到mysql
    AS 3.1 多library合并打包成aar的正确方式(fat-aar)
    Alexander的Python机器学习 之目录分析。
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13447099.html
Copyright © 2011-2022 走看看