[BZOJ1005][HNOI2008]明明的烦恼(prufer计数+组合数)
2017-12-03 21:21
519 查看
prufer序列链接:https://www.cnblogs.com/dirge/p/5503289.html
可以发现,这题是一个无根树计数的模型,可以利用prufer序列求解。如果不考虑每一个点的度数限制,那么结果就是nn−2,而根据prufer序列的构造方法能够得到,对于任意一个点i,i在prufer序列中的出现次数,等于点i的度数减1。
这时候,就变成了在n−2个值中选D1−1个值,定为1,再在剩下的n−1−D1中选D2−1个值,定为2,然后在剩下的n−D1−D2中选出D3−1个值定为3,……,最后还没确定的值,可以定为1到<
ba1b
span style="display: inline-block; position: relative; width: 0.589em; height: 0px; font-size: 125%;">n中的任意数值。
这本来可以用组合数简单解决,然而这题偏偏是高精……
高精求组合数,可以用质因数分解的方法计算。
代码:
可以发现,这题是一个无根树计数的模型,可以利用prufer序列求解。如果不考虑每一个点的度数限制,那么结果就是nn−2,而根据prufer序列的构造方法能够得到,对于任意一个点i,i在prufer序列中的出现次数,等于点i的度数减1。
这时候,就变成了在n−2个值中选D1−1个值,定为1,再在剩下的n−1−D1中选D2−1个值,定为2,然后在剩下的n−D1−D2中选出D3−1个值定为3,……,最后还没确定的值,可以定为1到<
ba1b
span style="display: inline-block; position: relative; width: 0.589em; height: 0px; font-size: 125%;">n中的任意数值。
这本来可以用组合数简单解决,然而这题偏偏是高精……
高精求组合数,可以用质因数分解的方法计算。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef long long ll; const int N = 1005, M = 905, ZZQ = 1e6; int n, m, sm, dm, d , cnt , pn, pri , pw , sum ; bool vis ; void calc(int n, int sgn) { int i; for (i = 1; i <= pn; i++) cnt[i] += sgn * sum [i]; } struct cyx { int n; ll a ; cyx() {} cyx(int _n) : n(_n) {memset(a, 0, sizeof(a));} }; cyx num(int a) { cyx res = cyx(1); res.a[1] = a; return res; } cyx prod(cyx a, cyx b) { int i, j; cyx res = cyx(a.n + b.n + 2); for (i = 1; i <= a.n; i++) for (j = 1; j <= b.n; j++) res.a[i + j - 1] += a.a[i] * b.a[j]; for (i = 1; i <= res.n; i++) res.a[i + 1] += res.a[i] / ZZQ, res.a[i] %= ZZQ; while (res.n > 1 && !res.a[res.n]) res.n--; return res; } cyx qpow(cyx a, int b) { cyx res = num(1); while (b) { if (b & 1) res = prod(res, a); a = prod(a, a); b >>= 1; } return res; } void write(cyx a) { int i; for (i = a.n; i; i--) if (i == a.n) printf("%d", a.a[i]); else printf("%06d", a.a[i]); printf("\n"); } int main() { int i, j; n = read(); for (i = 1; i <= n; i++) d[i] = read(); for (i = 2; i * i <= 1000; i++) { if (vis[i]) continue; for (j = i * i; j <= 1000; j += i) vis[j] = 1; } for (i = 2; i <= 1000; i++) if (!vis[i]) pri[++pn] = i; for (i = 1; i <= 1000; i++) for (j = 1; j <= pn; j++) { int x = i; while (x % pri[j] == 0) pw[i][j]++, x /= pri[j]; sum[i][j] = sum[i - 1][j] + pw[i][j]; } if (n == 1) return printf("%d\n", (d[1] == 0 || d[1] == -1)), 0; if (n == 2) return printf("%d\n", ((d[1] == 1 || d[1] == -1) && (d[2] == 1 || d[2] == -1))), 0; for (i = 1; i <= n; i++) if (d[i] < -1 || d[i] == 0) return puts("0"), 0; for (i = 1; i <= n; i++) if (d[i] != -1) sm += (--d[i]); else m++; if (sm > n - 2 || (!m && sm != n - 2)) return puts("0"), 0; dm = n - 2; sm = dm - sm; calc(dm, 1); for (i = 1; i <= n; i++) if (d[i] != -1) calc(d[i], -1), dm -= d[i]; calc(dm, -1); cyx ans = num(1); for (i = 1; i <= pn; i++) ans = prod(ans, qpow(num(pri[i]), cnt[i])); ans = prod(ans, qpow(num(m), sm)); write(ans); return 0; }
相关文章推荐
- 【BZOJ1005】明明的烦恼(HNOI2008)-Prufer序列+组合计数+高精度
- BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)
- bzoj1005: [HNOI2008]明明的烦恼 [prufer序列]
- 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度
- 【bzoj1005】[HNOI2008]明明的烦恼 Prufer序列+高精度
- bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&&生成树计数
- [bzoj1005]:[HNOI2008]明明的烦恼(prufer序列+质因数分解+高精乘)
- [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】
- [BZOJ1005]HNOI2008 明明的烦恼|prufer编码|排列组合
- bzoj1005 [HNOI2008]明明的烦恼(prufer序列+组合数学+高精)
- BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)
- [prufer序列]BZOJ1005: [HNOI2008]明明的烦恼
- BZOJ 1005 [HNOI2008]明明的烦恼 Prufer序列 Python
- Prufer编码 & [bzoj 1005] [HNOI2008]明明的烦恼:Prufer编码,组合数学,高精度
- BZOJ 1005: [HNOI2008]明明的烦恼(prufer序列->无根树表达)
- 【BZOJ 1005】[HNOI2008]明明的烦恼 【Prufer序列】
- [BZOJ1005][HNOI2008]明明的烦恼(prufer序列+组合数学+高精度)
- 【BZOJ1005】【HNOI2008】明明的烦恼
- bzoj 1005 [HNOI2008] 明明的烦恼 题解
- 【bzoj1005】[HNOI2008]明明的烦恼