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; }