zoukankan      html  css  js  c++  java
  • 「雅礼集训2018」树

    传送门

    我们不难发现,(1) 号点和 (2) 号点肯定是固定了形态的。

    那么我们就考虑从这两个节点的状态开始转移。

    (dp_{i, j}) 表示树的总大小为 (i),深度为 (j) 的方案数。

    那么答案就是 (frac{1}{(n - 1)!}sum_{i = 1} ^ n dp_{n, i} imes i),根据期望的线性性可得。

    那么我们考虑如何转移:

    首先我们显然有 (dp_{1, 1} = dp_{2, 2} = 1)

    对于 (dp_{i, j}) ,我们有两种转移:

    [dp_{i, j} = egin{cases} sum_{k = 1}^{i - 2} sum_{l = 1}^k {i - 2 choose k - 1} imes dp_{k, l} imes dp_{i - k, j}\ sum_{k = 1}^{i - 1} sum_{l = 1}^j {i - 2 choose k - 1} imes dp_{k, j} imes dp_{i - k, l}\ end{cases} ]

    第一种转移中,我们考虑枚举 (2) 节点的子树(不包括本身)的大小,然后钦定最大深度不在这部分子树里面,第二种转移反之。

    记得要用 doubleint 算两次答案。

    参考代码:

    #include <algorithm>
    #include <cstdio>
    using namespace std;
    
    const int _ = 30;
    
    int n, p, C[_][_];
    
    namespace task1 {
        double dp[_][_];
    	
        double fac(int x) {
            double res = 1.0;
            for (int i = 1; i <= x; ++i) res = res * i;
            return res;
    	}
    	
        void main() {
            dp[1][1] = dp[2][2] = 1;
            for (int i = 3; i <= n; ++i)
                for (int j = 2; j <= i; ++j) {
                    for (int k = 1; k <= i - 2; ++k)
                        for (int l = 1; l <= min(j - 2, k); ++l)
                            dp[i][j] += dp[k][l] * dp[i - k][j] * C[i - 2][k - 1];
                    for (int k = 1; k <= i - 1; ++k)
                        for (int l = 1; l <= j; ++l)
                            dp[i][j] += dp[k][j - 1] * dp[i - k][l] * C[i - 2][k - 1];
                }
            double ans = 0;
            for (int i = 1; i <= n; ++i) ans += i * dp[n][i];
            printf("%d
    ", (int) (ans / fac(n - 1) + 0.5));
        }
    }
    
    namespace task2 {
        int dp[_][_];
    
        int fac(int x) {
            int res = 1;
            for (int i = 1; i <= x; ++i) res = 1ll * res * i % p;
            return res;
        }
    	
        int power(int x, int k) {
            int res = 1;
            for (; k; k >>= 1, x = 1ll * x * x % p)
                if (k & 1) res = 1ll * res * x % p;
            return res % p;
        }
    
        void main() {
            dp[1][1] = dp[2][2] = 1;
            for (int i = 3; i <= n; ++i)
                for (int j = 2; j <= i; ++j) {
                    for (int k = 1; k <= i - 2; ++k)
                        for (int l = 1; l <= min(j - 2, k); ++l)
                            dp[i][j] = (dp[i][j] + 1ll * dp[k][l] * dp[i - k][j] % p * C[i - 2][k - 1] % p) % p;
                    for (int k = 1; k <= i - 1; ++k)
                        for (int l = 1; l <= j; ++l)
                            dp[i][j] = (dp[i][j] + 1ll * dp[k][j - 1] * dp[i - k][l] % p * C[i - 2][k - 1] % p) % p;
                }
            int ans = 0;
            for (int i = 1; i <= n; ++i)
                ans = (ans + 1ll * i * dp[n][i] % p) % p;
            printf("%lld
    ", 1ll * ans * power(fac(n - 1), p - 2) % p);
        }
    }
    
    int main() {
        scanf("%d %d", &n, &p);
        for (int i = 0; i <= n; ++i) C[i][0] = 1;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= i; ++j)
                C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
        task1 ::main();
        task2 ::main();
        return 0;
    }
    
  • 相关阅读:
    常见S1信令交互流程
    pthread_cond_wait避免线程空转
    sqlite:多线程操作数据库“database is locked”解决方法(二)
    sqlite:多线程操作数据库“database is locked”解决方法
    大端 小端
    关于天气分类的贝叶斯预测
    n 支队伍比赛,分别编号为 0,1,2。。。。n-1,已知它们之间的实力对比关系, 存储在一个二维数组 w[n][n]中,w[i][j] 的值代表编号为 i,j 的队伍中更强的一支。
    AC自动机 多模式匹配
    浮点数转换成二进制
    在一个缓冲去内实现三个栈,使用自有链表记录空闲块
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12900923.html
Copyright © 2011-2022 走看看