HDU 5379 Mahjong tree dfs+组合数学

时间:2023-03-08 21:51:42
HDU 5379 Mahjong tree  dfs+组合数学

题意:给你一棵树来分配号码,要求是兄弟节点连续并且每一棵子树连续。

思路:因为要求兄弟和子树都是连续的,所以自己打下草稿就可以发现如果一个节点有3个或3个以上的非叶子结点,那么就无论如何也不能达到目的。

    现在假设一个节点有x个非叶的子节点,y个叶子子节点。

    若x = 0,对于这棵子树,父节点只能取两端的号码才能使兄弟节点连续,y个叶子节点则有一个全排列,因此当前的方案数有 y! * 2

    若x = 1,且这颗非叶子节点构成的子树的方案数是f[a],方案数为 y! * f[a] * 2

    若x = 2,且这两棵非叶子结点的方案数分别是f[a]和f[b], 方案数为 y! * f[a] * f[b]

  

多校的题确实感觉有点难(不是指这道....),还是希望自己努点力,争取这一段时间把多校的题全部解决,,,除非特别难的。。。

 #pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define LL long long
#define MAXN 100005
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define eps 1e-8
using namespace std;
bool vis[MAXN];
vector<int> G[MAXN];
LL fact[MAXN];
LL res;
void dfs(int x){
vis[x] = true;
int single = , son = ;
//LL res = 1;
int m = G[x].size();
for(int i = ; i < m; i++){
int y = G[x][i];
if(vis[y]) continue;
vis[y] = true;
son++;
if(G[y].size() == ){
single++;
}
else{
dfs(y);
}
}
if(son - single > ){
res = ;
return;
}
else if(son - single == ){
res = res * fact[single] % MOD;
}
else{
res = res * 2LL * fact[single] % MOD;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // OPEN_FILE
int T;
scanf("%d", &T);
int cas = ;
fact[] = ;
for(int i = ; i <= ; i++){
fact[i] = fact[i - ] * (LL)i % MOD;
}
int n;
while(T--){
scanf("%d", &n);
int x, y;
for(int i = ; i <= n; i++){
G[i].clear();
}
memset(vis, , sizeof(vis));
for(int i = ; i < n; i++){
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
//vis[1] = true;
res = ;
//LL ans = dfs(1);
dfs();
if(n == ){
res = ;
}
printf("Case #%d: %I64d\n", cas++, res);
}
}