2015多校第7场 HDU 5379 Mahjong tree 构造,DFS

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5379

题意:一颗n个节点n-1条边的树,现在要给每个节点标号(1~n),要求:(1)每一层的兄弟节点的标号要是连续的(2)每一颗子树的所有节点标号是连续的。问有多少种标号方案。

解法:对于每一层顶多只能存在2个非叶子节点,否则无解;对于每一层有x个叶子节点,y个非叶子节点,那么ans=(ans * x!)%mod,另外如果y!=0,还得ans=2*ans%mod。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int mod = 1e9+7;
int head[maxn],edgecnt, ks;
bool flag;
struct edge{
    int to,next;
}E[maxn*2];
LL fac[maxn];
LL ans;
void init(){
    flag = 1;
    ans = 1;
    memset(head,-1,sizeof(head));
    edgecnt=0;
}
void INIT(){
    fac[0] = 1;
    for(int i=1; i<maxn; i++){
        fac[i] = fac[i-1]*i%mod;
    }
}
void add(int u,int v){
    E[edgecnt].to=v,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
LL dfs(int u, int pre){
    if(!flag) return 0;
    LL s = 1, all = 0, ss = 0;
    //all代表叶子节点
    //ss代表非叶子节点
    for(int i = head[u]; ~i; i=E[i].next){
        int to = E[i].to;
        if(to == pre) continue;
        LL x = dfs(to, u);
        s += x;
        if(x == 1) all++;
        else if(x>1) ss++;
    }
    if(ss>2) flag=false;
    else{
        ans=(ans*fac[all])%mod;
        if(ss!=0) ans=(ans*2LL)%mod;
    }
    return s;
}
int main()
{
    ks = 0;
    int T, n;
    INIT();
    scanf("%d", &T);
    while(T--){
        init();
        scanf("%d", &n);
        for(int i=1; i<n; i++){
            int u,v;
            scanf("%d %d", &u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1, -1);
        if(n>1) ans=ans*2;
        if(!flag) ans=0;
        printf("Case #%d: %lld\n", ++ks, ans%mod);
    }
    return 0;
}

 

posted @ 2017-08-07 20:06  zxycoder  阅读(152)  评论(0编辑  收藏  举报