zoukankan      html  css  js  c++  java
  • 计蒜客 Red Black Tree(树形DP)

    You are given a rooted tree with n nodes. The nodes are numbered 1..n. The root is node 1, and m of the nodes are colored red, the rest are black.

    You would like to choose a subset of nodes such that there is no node in your subset which is an ancestor of any other node in your subset. For example, if A is the parent of B and B is the parent of C, then you could have at most one of A, B or C in your subset. In addition, you would like exactly k of your chosen nodes to be red.

    If exactly mm of the nodes are red, then for all k = 0..m, figure out how many ways you can choose subsets with k red nodes, and no node is an ancestor of any other node.

    Input Format

    Each input will consist of a single test case.

    Note that your program may be run multiple times on different inputs.

    Each test case will begin with a line with two integers n(1n2×10^5) and m(0mmin(10^3,n)), where n is the number of nodes in the tree, and m is the number of nodes which are red. The nodes are numbered 1..n.

    Each of the next n - 1 lines will contain a single integer p(1pn), which is the number of the parent of this node. The nodes are listed in order, starting with node 2, then node 3, and so on. Node 1 is skipped, since it is the root. It is guaranteed that the nodes form a single tree, with a single root at node 1 and no cycles.

    Each of the next m lines will contain single integer r(1rn). These are the numbers of the red nodes. No value of r will be repeated.

    Output Format

    Output m + 1 lines, corresponding to the number of subsets satisfying the given criteria with a number of red nodes equal to k = 0..m, in that order. Output this number modulo 10^9 + 7.

    样例输入1

    4 1
    1
    1
    1
    3

    样例输出1

    5
    4

    样例输入2

    4 4
    1
    1
    1
    1
    2
    3
    4

    样例输出2

    1
    4
    3
    1
    0

    样例输入3

    14 4
    1
    2
    1
    2
    3
    4
    5
    5
    13
    8
    10
    4
    4
    8
    3
    12
    13

    样例输出3

    100
    169
    90
    16
    0

    题意

    一棵树,n个点,其中有m个红色,其余为黑点,1为根,选1个点集合,集合内的任意两点不互为祖先,问集合内红色节点的个数为0-m的方案数。

    题解

    dp[root][m]代表根为root的子树红色节点为m的方案数。

    不选root,dp[root][0]=1,考虑子树son的情况,考虑h[M]代表组成M的方案数,相当于每次一颗子树把里面的所有红色节点一个一个压进去,类似于背包。

    选root,dp[root][red[root]]++,相当于下面都不能选。

    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=200005;
     4 const int M=1005;
     5 const int MD=1000000007;
     6 int dp[N][M],h[M],red[N],sz[N];
     7 int n,m;
     8 vector<int>G[N];
     9 void dfs(int u){
    10     dp[u][0]=1;
    11     sz[u]=red[u];
    12     for(int i=0;i<G[u].size();i++) {
    13         int v=G[u][i];
    14         dfs(v);
    15         int up=min(sz[u]+sz[v],m);
    16         for(int j=0;j<=up;j++)h[j]=0;
    17         for(int j=0;j<=sz[v];j++)
    18             for(int k=0;k<=sz[u]&&j+k<=up;k++)
    19                 h[j+k]=(h[j+k]+1LL*dp[v][j]*dp[u][k])%MD;
    20         sz[u]+=sz[v];
    21         for(int j=0;j<=sz[u];j++)dp[u][j]=h[j];
    22     }
    23     dp[u][red[u]]=(dp[u][red[u]]+1)%MD;
    24 }
    25 int main() {
    26     scanf("%d%d",&n,&m);
    27     for(int i=2,u;i<=n;i++) {
    28         scanf("%d",&u);
    29         G[u].push_back(i);
    30     }
    31     for(int i=0,x;i<m;i++) {
    32         scanf("%d",&x);
    33         red[x]=1;
    34     }
    35     dfs(1);
    36     for(int i=0;i<=m;i++)
    37         printf("%d
    ",dp[1][i]);
    38     return 0;
    39 }
  • 相关阅读:
    ORA-00904:标识符无效
    SQL错误:ORA-12899
    ORA-01722:无效数字
    科学记数法
    报表软件公司悬赏 BUG,100块钱1个的真实用意
    Perl--包
    Perl--正则
    Perl use strict 控制变量
    Oracle不删除用户,导入数据
    从别人的角度理解这个世界——Leo鉴书80
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/11300110.html
Copyright © 2011-2022 走看看