您的位置:首页 > 其它

BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

2015-12-02 22:02 405 查看


知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)!

---------------------------------------------------------------------------

#include<cstdio>#include<algorithm>#include<cstring> using namespace std; typedef long long ll; const int maxn = 400; int d[maxn], N, m;int p[maxn], pn, cnt[maxn];bool F[maxn]; void Init() { pn = 0; memset(F, 0, sizeof F); for(int i = 2; i < maxn; i++) { if(!F[i]) p[pn++] = i; for(int j = 0; j < pn && i * p[j] < maxn; j++) { F[i * p[j]] = true; if(i % p[j] == 0) break; } }} void Calculate(int t, bool typ) { if(t < 2) return; for(int i = 2; i <= t; i++) for(int j = 0, v = i; j < pn && v != 1; j++) for(; v % p[j] == 0; v /= p[j], typ ? cnt[j]++ : cnt[j]--);} ll Power(ll x, int t) { ll ret = 1; for(; t; t >>= 1, x *= x) if(t & 1) ret *= x; return ret;} int main() { Init(); m = 0; scanf("%d", &N); for(int i = 0; i < N; i++) { scanf("%d", d + i); m += d[i] - 1; } if(m != N - 2) { puts("0"); return 0; } if(N == 1 && !d[0]) { puts("1"); return 0; } for(int i = 0; i < N; i++) if(!d[i]) { puts("0"); return 0; } memset(cnt, 0, sizeof cnt); Calculate(m, 1); for(int i = 0; i < N; i++) Calculate(d[i] - 1, 0); ll ans = 1; for(int i = 0; i < pn; i++) if(cnt[i]) ans *= Power(ll(p[i]), cnt[i]); printf("%lld\n", ans); return 0;}---------------------------------------------------------------------------

1211: [HNOI2004]树的计数

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1752 Solved: 578
[Submit][Status][Discuss]

Description

一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵。给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di的树的个数。

Input

第一行是一个正整数n,表示树有n个结点。第二行有n个数,第i个数表示di,即树的第i个结点的度数。其中1<=n<=150,输入数据保证满足条件的树不超过10^17个。

Output

输出满足条件的树有多少棵。

Sample Input

4
2 1 2 1

Sample Output

2

HINT

Source

组合数学
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: