题意:给你一棵树来分配号码,要求是兄弟节点连续并且每一棵子树连续。
思路:因为要求兄弟和子树都是连续的,所以自己打下草稿就可以发现如果一个节点有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]
多校的题确实感觉有点难(不是指这道....),还是希望自己努点力,争取这一段时间把多校的题全部解决,,,除非特别难的。。。
1 #pragma comment(linker, "/STACK:102400000,102400000") 2 #include <iostream> 3 #include <cstdio> 4 #include <fstream> 5 #include <algorithm> 6 #include <cmath> 7 #include <deque> 8 #include <vector> 9 #include <queue> 10 #include <string> 11 #include <cstring> 12 #include <map> 13 #include <stack> 14 #include <set> 15 #define LL long long 16 #define MAXN 100005 17 #define INF 0x3f3f3f3f 18 #define MOD 1000000007 19 #define eps 1e-8 20 using namespace std; 21 bool vis[MAXN]; 22 vector<int> G[MAXN]; 23 LL fact[MAXN]; 24 LL res; 25 void dfs(int x){ 26 vis[x] = true; 27 int single = 0, son = 0; 28 //LL res = 1; 29 int m = G[x].size(); 30 for(int i = 0; i < m; i++){ 31 int y = G[x][i]; 32 if(vis[y]) continue; 33 vis[y] = true; 34 son++; 35 if(G[y].size() == 1){ 36 single++; 37 } 38 else{ 39 dfs(y); 40 } 41 } 42 if(son - single > 2){ 43 res = 0; 44 return; 45 } 46 else if(son - single == 2){ 47 res = res * fact[single] % MOD; 48 } 49 else{ 50 res = res * 2LL * fact[single] % MOD; 51 } 52 } 53 int main() 54 { 55 #ifndef ONLINE_JUDGE 56 freopen("in.txt", "r", stdin); 57 //freopen("out.txt", "w", stdout); 58 #endif // OPEN_FILE 59 int T; 60 scanf("%d", &T); 61 int cas = 1; 62 fact[0] = 1; 63 for(int i = 1; i <= 100000; i++){ 64 fact[i] = fact[i - 1] * (LL)i % MOD; 65 } 66 int n; 67 while(T--){ 68 scanf("%d", &n); 69 int x, y; 70 for(int i = 0; i <= n; i++){ 71 G[i].clear(); 72 } 73 memset(vis, 0, sizeof(vis)); 74 for(int i = 1; i < n; i++){ 75 scanf("%d%d", &x, &y); 76 G[x].push_back(y); 77 G[y].push_back(x); 78 } 79 //vis[1] = true; 80 res = 1; 81 //LL ans = dfs(1); 82 dfs(1); 83 if(n == 1){ 84 res = 1; 85 } 86 printf("Case #%d: %I64d ", cas++, res); 87 } 88 }