hdu 5379

来源:互联网 发布:网络美术培训哪个好 编辑:程序博客网 时间:2024/06/06 02:23

题意:有一棵有n个节点的树,有编号1~n的n个数字要放到树上,且要满足三个要求:
1.树的每个节点只放一个数字
2.树的任意一个节点的所有直接孩子节点上面放的数字排序后是连续的
3.一棵子树的所有节点上面放的数字排序后是连续的
问有多少种不同的放法,结果取模1e9+7。
题解:因为子树的数字排序后都是连续的,所以可以转化为求切割连续区间的方法数。要加开栈外挂才能过。

#pragma comment(linker, "/STACK:102400000,102400000")#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;const int N = 100005;const long long MOD = 1e9 + 7;vector<int> g[N];long long A[N], res;int dfs(int u, int fa) {    int tot = 1, ns = 0, nt = 0;//包含根节点的所有节点,直接孩子节点,子树个数    int n = g[u].size();    for (int i = 0; i < n; i++) {        int v = g[u][i];        if (v == fa)            continue;        ns++;           int num = dfs(v, u);        if (num > 1)            nt++;        tot += num;    }    if (nt > 2)//有大于两个子树无法保证切割后连续        return res = 0;    if (nt)//有一个或两个子树切割方法数都只有两个        res = res * 2 % MOD;    res = res * A[ns - nt] % MOD;//当个节点可自由排序    return tot;}int main() {    A[0] = 1;    for (int i = 1; i < N; i++)        A[i] = A[i - 1] * i % MOD;    int t, cas = 1, n;    scanf("%d", &t);    while (t--) {        scanf("%d", &n);        for (int i = 0; i <= n; i++)            g[i].clear();        int a, b;        for (int i = 0; i < n - 1; i++) {            scanf("%d%d", &a, &b);            g[a].push_back(b);            g[b].push_back(a);          }        if (n == 1) {            printf("Case #%d: 1\n", cas++);            continue;           }        res = 1;        dfs(1, 0);        printf("Case #%d: %lld\n", cas++, res * 2 % MOD);//根节点左右两种切法    }    return 0;}
0 0
原创粉丝点击