Mahjong tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 175 Accepted Submission(s): 51
Problem Description
Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn't look good. So he wants to decorate the tree.(The tree has n vertexs, indexed from 1 to n.)
Thought for a long time, finally he decides to use the mahjong to decorate the tree.
His mahjong is strange because all of the mahjong tiles had a distinct index.(Little sun has only n mahjong tiles, and the mahjong tiles indexed from 1 to n.)
He put the mahjong tiles on the vertexs of the tree.
As is known to all, little sun is an artist. So he want to decorate the tree as beautiful as possible.
His decoration rules are as follows:
(1)Place exact one mahjong tile on each vertex.
(2)The mahjong tiles' index must be continues which are placed on the son vertexs of a vertex.
(3)The mahjong tiles' index must be continues which are placed on the vertexs of any subtrees.
Now he want to know that he can obtain how many different beautiful mahjong tree using these rules, because of the answer can be very large, you need output the answer modulo 1e9 + 7.
Input
The first line of the input is a single integer T, indicates the number of test cases.
For each test case, the first line contains an integers n. (1 <= n <= 100000)
And the next n - 1 lines, each line contains two integers ui and vi, which describes an edge of the tree, and vertex 1 is the root of the tree.
Output
For each test case, output one line. The output format is "Case #x: ans"(without quotes), x is the case number, starting from 1.
Sample Input
2
9
2 1
3 1
4 3
5 3
6 2
7 4
8 7
9 3
8
2 1
3 1
4 3
5 1
6 4
7 5
8 4
Sample Output
Source
2015 Multi-University Training Contest 7
每个结点的孩子的id要连续,每个子树的id要连续。
因此每个结点的子树中,不能有超过两个规模大于1的子树。否则是无法安排的。
根据如此。给一个连续区间,子树的根的值由父亲决定。
在一个区间中,规模大于1的子树必然选择的是最左边或者最右边的连续的id值,
并且直接子节点id是左区间最大值,或者右区间最小值。剩下规模为1的子树,有N!种安排方法。
对于一棵子树分三种情况:
在代码中讨论
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define maxn 100007
vector<int>head[maxn];
vector<int>son[maxn];
ll size[maxn];
ll mod = 1000000007;
ll jie[maxn];
ll dfs(int u,int f){
size[u] = 1;
ll ans = 1;
int son2 = 0,son1 = 0;
for(int i = 0;i < head[u].size(); i++){
int v = head[u][i];
if(v == f) continue;
ans = ans*dfs(v,u)%mod;
if(ans == 0) return 0; //答案等于0,则无解直接返回
if(size[v] > 1) son2++;
else son1++;
if(son2 > 2) return 0;
size[u] += size[v];
}
if(son2 == 2 ){ //两个规模大于1的子树,可以安排他们在最左,最右的位置,两种
ans = ans*2%mod;
}
else if( son2 == 1 && son1 > 0) //存在规模大于1的子树和只有1的子树,安排大子树使用在左边,或者右边的连续id
ans = ans*2%mod;
else if( son2 == 1 && son1 == 0 )//规模大于1的子树只有1个,那么该子树的根选最小值,最大值都可以。跟总根一样
ans = ans*2%mod;
ans = ans*jie[son1]%mod;
return ans;
}
int main(){
int t,n;
scanf("%d",&t);
jie[0] = 1;//处理阶乘的值
for(int i = 1;i < maxn; i++){
jie[i] = jie[i-1]*i%mod;
}
int tt = 1;
while(t--){
scanf("%d",&n);
memset(size,0,sizeof(size));
for(int i = 1;i <= n; i++)
head[i].clear();
int u,v;
for(int i = 1;i < n; i++){
scanf("%d%d",&u,&v);
head[u].push_back(v);
head[v].push_back(u);
}
ll ans = dfs(1,0);
if(size[1] > 1) ans = ans*2%mod; //如果树的规模大于1,根可以选最小值,或者最大值的id
printf("Case #%d: %I64d\n",tt++,ans);
}
return 0;
}