BZOJ1005: [HNOI2008]明明的烦恼
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0
Sample Input
3
1
-1
-1
1
-1
-1
Sample Output
2
HINT
两棵树分别为1-2-3;1-3-2
该题运用到了树的prufer编码的性质:
(1)树的prufer编码的实现
不断 删除树中度数为1的最小序号的点,并输出与其相连的节点的序号 直至树中只有两个节点
(2)通过观察我们可以发现
任意一棵n节点的树都可唯一的用长度为n-2的prufer编码表示
度数为m的节点的序号在prufer编码中出现的次数为m-1
(3)怎样将prufer编码还原为一棵树??
从prufer编码的最前端开始扫描节点,设该节点序号为 u ,寻找不在prufer编码的最小序号且没有被标记的节点 v ,连接 u,v,并标记v,将u从prufer编码中删除。扫描下一节点。
该题需要将树转化为prufer编码:
n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数。
则
所以要求在n-2大小的数组中插入tot各序号,共有种插法;
在tot各序号排列中,插第一个节点的方法有种插法;
插第二个节点的方法有种插法;
………
另外还有m各节点无度数限制,所以它们可任意排列在剩余的n-2-tot的空间中,排列方法总数为;
根据乘法原理:
然后就要高精度了…..但高精度除法太麻烦了,显而易见的排列组合一定是整数,所以可以进行质因数分解,再做一下相加减。
关于n!质因数分解有两种方法,第一种暴力分解,这里着重讲第二种。
若p为质数,则n!可分解为 一个数*,其中且 <n
所以
——转自怡红公子
链接:http://www.cnblogs.com/noip/archive/2013/03/10/2952520.html
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 struct bignum { 5 int l, a[10000]; 6 7 bignum (int t) { 8 l = 0; memset(a, 0, sizeof(0)); 9 while (t != 0) { 10 a[++l] = t % 10000; 11 t /= 10000; 12 } 13 if (l == 0) l = 1; 14 } 15 16 void mul(int k) { 17 for (int i = 1; i <= l; i++) 18 a[i] *= k; 19 for (int i = 1; i <= l; i++) 20 if (a[i] >= 10000) { 21 int t = i; 22 do { 23 a[t + 1] += a[t] / 10000; 24 a[t++] %= 10000; 25 } while (a[t] >= 10000); 26 } 27 while (a[l + 1] > 0) l++; 28 } 29 30 void print() { 31 printf("%d", a[l]); 32 for (int i = l - 1; i >= 1; i--) 33 printf("%04d", a[i]); 34 printf("\n"); 35 } 36 }; 37 int n, m = 0, tot = 0, d[1001], prime[1001], cnt[1001]; 38 39 bool judge(int k) { 40 for (int i = 2; i <= sqrt(k); i++) 41 if (k % i == 0) return false; 42 return true; 43 } 44 45 void makelist(int n) { 46 prime[0] = 0; 47 for (int i = 2; i <= n; i++) 48 if (judge(i)) prime[++prime[0]] = i; 49 } 50 51 void compute(int k, int t) { 52 for (int i = 1; i <= prime[0] && prime[i] <= k; i++) { 53 int x = 0, n = k, p = prime[i]; 54 while (n != 0) { 55 x += n / p; 56 n /= p; 57 } 58 cnt[i] += x * t; 59 } 60 } 61 62 int main() { 63 //freopen("input.txt", "r", stdin); 64 //freopen("output.txt", "w", stdout); 65 scanf("%d", &n); 66 for (int i = 1; i <= n; i++) { 67 scanf("%d", &d[i]); 68 if (d[i] == -1) m++; 69 else tot += d[i] - 1; 70 } 71 72 makelist(n); 73 memset(cnt, 0, sizeof(cnt)); 74 compute(n - 2, 1); 75 compute(n - 2 - tot, -1); 76 for (int i = 1; i <= n; i++) 77 if (d[i] != -1) compute(d[i] - 1, -1); 78 79 bignum ans = 1; 80 for (int i = 1; i <= prime[0]; i++) 81 for (int j = 1; j <= cnt[i]; j++) 82 ans.mul(prime[i]); 83 for (int i = 1; i <= n - 2 - tot; i++) 84 ans.mul(m); 85 ans.print(); 86 return 0; 87 }