bzoj1005: [HNOI2008]明明的烦恼 prufer编码
2018-03-04 15:59
225 查看
bzoj1005: [HNOI2008]明明的烦恼
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣……给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0Sample Input
31
-1
-1
Sample Output
2HINT
两棵树分别为1-2-3;1-3-2分析
这道题是一道prufer编码的题,关于prufer编码的学习,推荐一篇文章:prufer编码学习然后开始推公式
首先我们考虑所有点的度数都确定的情况。
prufer序列中每个数字出现的次数是di−1di−1,于是全排列然后再分别排列即可得出以下式子
(di−1)!" role="presentation" style="text-align: center; position: relative;">ans=(n−2)!∏(di−1)!ans=(n−2)!∏(di−1)!
然而只有部分是确定的。所以我们先考虑确定的一部分,假设有cnt个,那么它们在prufer序列中占位子一共有
sum=∏1cntdi−1sum=∏1cntdi−1
我们在长度为n-2的prufer序列中挑sum个位子给这些确定的数,在乘以这些确定的数本身的方案数就是这些数的答案,即
Csumn−2⋅sum!∏1cnt(di−1)!Cn−2sum⋅sum!∏1cnt(di−1)!
剩下的空位有n-sum-2个,每一个位置共有n-cnt种选择,产生的贡献是。
(n−cnt)n−sum−2(n−cnt)n−sum−2
所以总的答案就是
ans=Csumn−2⋅sum!∏1cnt(di−1)!⋅(n−cnt)n−sum−2ans=Cn−2sum⋅sum!∏1cnt(di−1)!⋅(n−cnt)n−sum−2
=(n−2)!⋅(n−cnt)n−sum−2∏1cnt(di−1)!⋅(n−sum−2)!=(n−2)!⋅(n−cnt)n−sum−2∏1cnt(di−1)!⋅(n−sum−2)!
这个东西会爆longlong,质因数分解然后高精度一下即可。
/************************************************************** Problem: 1005 User: 2014lvzelong Language: C++ Result: Accepted Time:52 ms Memory:1312 kb ****************************************************************/ #include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int read() { char ch = getchar(); int x = 0, f = 1; for(;ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1; for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch; return x * f; } const int N = 1100; int n, tot, cnt, sum, pri , mn , a , t ; bool vis ; void GP(int N) { for(int i = 2;i <= N; ++i) { if(!mn[i]) pri[++tot] = i, mn[i] = tot; for(int j = 1;j <= tot && i * pri[j] <= N; ++j) { mn[i * pri[j]] = j; if(!(i % pri[j])) break; } } } void add(int b, int f) { for(int j = mn[b]; b != 1; j = mn[b]) for(;!(b % pri[j]); b /= pri[j]) a[j] += f; } void mul(int x) { for(int i = 1;i <= t[0]; ++i) t[i] *= x; for(int j = 1;j < t[0]; ++j) { t[j + 1] += t[j] / 10; t[j] %= 10; } for(;t[t[0]] >= 10; ++t[0]) { t[t[0] + 1] = t[t[0]] / 10; t[t[0]] %= 10; } } int main() { n = read(); GP(1000); t[0] = t[1] = 1; if(n == 1) { int x = read(); if(!x) puts("1"); else puts("0"); return 0; } for(int i = 1;i <= n; ++i) { int t = read(); if(!t) return puts("0") * 0; if(~t) { ++cnt; sum += --t; for(int i = 1;i <= t; ++i) add(i, -1); } } if(sum > n - 2) return puts("0") * 0; for(int i = n - 1 - sum; i <= n - 2; ++i) add(i, 1); for(int i = 1;i <= tot; ++i) while(a[i]--) mul(pri[i]); for(int i = 1;i <= n - 2 - sum; ++i) mul(n - cnt); for(int i = t[0]; i; --i) printf("%d", t[i]); puts(""); return 0; }
相关文章推荐
- BZOJ1005--[HNOI2008]明明的烦恼(树的prufer编码)
- bzoj1005: [HNOI2008]明明的烦恼
- BZOJ1005: [HNOI2008]明明的烦恼
- Prufer编码 & [bzoj 1005] [HNOI2008]明明的烦恼:Prufer编码,组合数学,高精度
- [bzoj 1005][HNOI 2008]明明的烦恼(prufer数列+排列组合)
- bzoj1005 [HNOI2008]明明的烦恼 prufer+组合数学
- 【BZOJ 1005】[HNOI2008]明明的烦恼 【Prufer序列】
- [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】
- [prufer序列]BZOJ1005: [HNOI2008]明明的烦恼
- bzoj1005 [HNOI2008]明明的烦恼
- 【BZOJ】【1005】【HNOI2008】明明的烦恼
- 【bzoj 1005】 明明的烦恼 【HNOI2008】
- 【Purfer】【bzoj 1005】: [HNOI2008]明明的烦恼
- 【HNOI2008】bzoj1005 明明的烦恼
- bzoj 1005: [HNOI2008]明明的烦恼 组合数学 + purfer序列
- bzoj1005 [HNOI2008]明明的烦恼(prufer序列+组合数学+高精)
- BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数
- BZOJ 1005: [HNOI2008]明明的烦恼(prufer数列)
- 【bzoj1005】[HNOI2008]明明的烦恼
- BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)