zoukankan      html  css  js  c++  java
  • HDU 4359 Easy Tree DP? 组合数学+动归

    题意:定义一种树,每个节点的权值都是20到2n-1,每个权值出现一次,每个节点的左子树的权值和小于右子树,除非只有一个子树。给你n和d,问有n个节点且恰好深度是d的这种树有多少种。

    比赛的时候我没有做出来,当时A的人还是不少,

    有一个超傻逼的居然没想到,就是  ,这表示一个权值较大的节点是大于所有权值小于他的值之和的。

    所以对于每一个合法的树,只要把权值最大的放到右子树就可以满足了。

    动归过程:f[i][j]表示i个节点深度不超过j的方案种数。

    for (int i = 2; i <= N; i++){
            for (int j = 1; j <= N; j++){
                f[i][j] = (2 * i * f[i - 1][j - 1]) % MOD;
                for (int k = 1; k < i - 1; k++){
                    f[i][j] = (f[i][j] + ((C[i][i - 1] * C[i - 2][k]) % MOD) * ((f[k][j - 1] * f[i - k - 1][j - 1]) % MOD)) % MOD;
                }
            }
        }

    对于根节点分两种情况,只有一个子树,或者左右子树都有。

    如果只有一个子树,那么f[i][j] = i * f[i-1][j-1] * 2。 意思就是任取一个节点做根节点,然后把满足条件的f[i-1][j-1]作为根节点的子树,左右两个子树所以再乘以2.

    如果左右子树都有,情况稍微麻烦一点,那么就枚举左子树中的节点个数k,1≤k≤i-2,对于每一个k,还是任选一个节点做根节点,然后在除了根节点和剩下的最大值外的i-2个点中选k个到左子树,剩下的自然就到右子树了。这是节点的分配,那方案数呢,左子树有k个节点,深度不超过j-1,就是f[k][j-1],右子树有i-k-1各节点,深度同样不超过j-1,就是f[i-k-1][j-1],然后将这些乘起来就得到总的方案数了,所以有了下面总的状态转移方程。

    f[i][j] = 2*i*f[i - 1][j - 1] + (i*C[i - 2][k]*f[k][j - 1]*f[i - k - 1][j - 1])(1≤k≤i-2)

    其实还是蛮简单的啊,为什么当时不会做呢???智商被压制的感觉特别不爽

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <fstream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <deque>
     7 #include <vector>
     8 #include <queue>
     9 #include <string>
    10 #include <cstring>
    11 #include <map>
    12 #include <stack>
    13 #include <set>
    14 #define LL long long
    15 #define eps 1e-8
    16 #define INF 0x3f3f3f3f
    17 #define OPEN_FILE
    18 #define MAXN 400
    19 using namespace std;
    20 LL f[MAXN][MAXN], C[MAXN][MAXN];
    21 const LL MOD = 1e9 + 7;
    22 const int N = 360;
    23 int main()
    24 {
    25     //freopen("in.txt","r",stdin);
    26     //freopen("out.txt","w",stdout);
    27     memset(C, 0, sizeof(C));
    28     C[0][0] = 1;
    29     for (int i = 1; i <= N; i++){
    30         C[i][0] = 1;
    31         for (int j = 1; j <= i; j++){
    32             C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    33         }
    34     }
    35     memset(f, 0, sizeof(f));
    36     for (int i = 1; i <= N; i++){
    37         f[1][i] = 1;
    38     }
    39     for (int i = 2; i <= N; i++){
    40         for (int j = 1; j <= N; j++){
    41             f[i][j] = (2 * i * f[i - 1][j - 1]) % MOD;
    42             for (int k = 1; k < i - 1; k++){
    43                 f[i][j] = (f[i][j] + ((i * C[i - 2][k]) % MOD) * ((f[k][j - 1] * f[i - k - 1][j - 1]) % MOD)) % MOD;
    44             }
    45         }
    46     }
    47     int T;
    48     scanf("%d", &T);
    49     int n, d;
    50     for (int cas = 1; cas <= T; cas++){
    51         scanf("%d%d", &n, &d);
    52         printf("Case #%d: %I64d
    ", cas, (f[n][d] - f[n][d - 1] + MOD) % MOD);
    53     }
    54     return 0;
    55 }
  • 相关阅读:
    git 学习
    公司领导写给新员工的信
    PLSQl远程连接oracle数据库
    hdu2222之AC自动机入门
    代码中添加事务控制 VS(数据库存储过程+事务) 保证数据的完整性与一致性
    ubuntu13.04安装SenchaArchitect-2.2无法启动的问题
    MVVMLight Toolkit在Windows Phone中的使用扩展之一:在ViewModel中实现导航,并传递参数
    面试题24:二叉搜索树与双向链表
    Struts2中的包的作用描述
    filter-mapping中的dispatcher使用
  • 原文地址:https://www.cnblogs.com/macinchang/p/4700451.html
Copyright © 2011-2022 走看看