【BZOJ1005】【HNOI2008】明明的烦恼
2018-02-04 19:42
302 查看
【题目链接】
点击打开链接
【双倍经验链接】
【BZOJ1211】【HNOI2004】树的计数
【思路要点】
考虑树的Prufer序列。
树的Prufer是一个长度为\(N-2\)的序列,其中每一个元素为一个\(1\)到\(N\)的整数。
每一个这样的序列对应了一棵确定的\(N\)个节点的树,并且每一棵\(N\)个节点的树对应了一个这样的序列。换而言之,Prufer序列和树一一对应。
Prufer序列存在性质:一个节点\(i\)在树上的的度数等于其在Prufer序列中出现的次数\(+1\)。
那么问题就变成了简单的组合数学题,稍加分析即可轻松解决,在此不再赘述。
问题不要求取模,因此需要高精度运算。
直接实现除法的代价较高,可以采取记录各个质因数的个数来避免除法运算。
时间复杂度\(O(N^{2})\)
【代码】
点击打开链接
【双倍经验链接】
【BZOJ1211】【HNOI2004】树的计数
【思路要点】
考虑树的Prufer序列。
树的Prufer是一个长度为\(N-2\)的序列,其中每一个元素为一个\(1\)到\(N\)的整数。
每一个这样的序列对应了一棵确定的\(N\)个节点的树,并且每一棵\(N\)个节点的树对应了一个这样的序列。换而言之,Prufer序列和树一一对应。
Prufer序列存在性质:一个节点\(i\)在树上的的度数等于其在Prufer序列中出现的次数\(+1\)。
那么问题就变成了简单的组合数学题,稍加分析即可轻松解决,在此不再赘述。
问题不要求取模,因此需要高精度运算。
直接实现除法的代价较高,可以采取记录各个质因数的个数来避免除法运算。
时间复杂度\(O(N^{2})\)
【代码】
/*Program till line 174*/ #include<bits/stdc++.h> using namespace std; #define MAXL 4005 #define MAXN 1005 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct INT {int len, value[MAXL]; }; INT operator + (INT a, INT b) { INT res; res.len = max(a.len, b.len); memset(res.value, 0, sizeof(res.value)); for (int i = 0; i <= res.len; i++) res.value[i] = a.value[i] + b.value[i]; for (int i = 0; i <= res.len; i++) { res.value[i + 1] += res.value[i] / 10; res.value[i] %= 10; } if (res.value[res.len + 1]) res.len++; return res; } INT operator - (INT a, INT b) { INT res; res.len = a.len; memset(res.value, 0, sizeof(res.value)); for (int i = 0; i <= res.len; i++) res.value[i] = a.value[i] - b.value[i]; for (int i = 0; i <= res.len; i++) if (res.value[i] < 0) { res.value[i] += 10; res.value[i + 1]--; } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT operator * (INT a, INT b) { INT res; res.len = a.len + b.len; for (int i = 0; i <= res.len; i++) res.value[i] = 0; for (int i = 1; i <= a.len; i++) for (int j = 1; j <= b.len; j++) res.value[i + j - 1] += a.value[i] * b.value[j]; for (int i = 0; i <= res.len; i++) { res.value[i + 1] += res.value[i] / 10; res.value[i] %= 10; } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT number(int x) { INT res; res.len = 0; if (x == 0) res.len = 1, res.value[1] = 0; memset(res.value, 0, sizeof(res.value)); while (x) { res.value[++res.len] = x % 10; x /= 10; } return res; } INT ten(int x) { INT res; res.len = x + 1; res.value[res.len] = 1; for (int i = 0; i < res.len; i++) res.value[i] = 0; return res; } bool operator >= (INT a, INT b) { if (a.len > b.len) return true; if (a.len < b.len) return false; for (int i = a.len; i >= 1; i--) { if (a.value[i] > b.value[i]) return true; if (a.value[i] < b.value[i]) return false; } return true; } INT operator / (INT a, INT b) { INT res, tmp; res.len = a.len - b.len + 1; for (int i = res.len; i >= 1; i--) { tmp = ten(i - 1) * b; while (a >= tmp) { res.value[i]++; a = a - tmp; } } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT operator ^ (INT a, int b) { if (b == 0) return number(1); INT res = a ^ (b / 2); if (b % 2 == 0) return res * res; else return res * res * a; } void print(INT x) { for (int i = x.len; i >= 1; i--) printf("%d", x.value[i]); printf("\n"); } int tot, prime[MAXN], f[MAXN], a[MAXN], num[MAXN]; void add(int x) { while (x != 1) { a[num[f[x]]]++; x /= f[x]; } } void dec(int x) { while (x != 1) { a[num[f[x]]]--; x /= f[x]; } } int main() { int n; read(n); for (int i = 2; i <= n; i++) { if (f[i] == 0) { prime[++tot] = f[i] = i; num[i] = tot; } for (int j = 1; j <= tot && prime[j] <= f[i]; j++) { int tmp = i * prime[j]; if (tmp > n) break; f[tmp] = prime[j]; } } for (int i = 1; i <= n - 2; i++) add(i); int cnt = 0, lft = n - 2; for (int i = 1; i <= n; i++) { int x; read(x); if (x == 0 || x <= -2) { writeln(0); return 0; } if (x == -1) cnt++; else { x--; if (x > lft) { writeln(0); return 0; } lft -= x; for (int i = 1; i <= x; i++) dec(i); } } for (int i = 1; i <= lft; i++) dec(i); static INT ans = number(1), tmp; for (int i = 1; i <= tot; i++) ans = ans * (number(prime[i]) ^ a[i]); if (cnt == 0) tmp = number(1); else tmp = number(cnt); ans = ans * (tmp ^ lft); print(ans); return 0; } /*Original program, TLE with large constant but clearer*/ #include<bits/stdc++.h> using namespace std; #define MAXL 4005 #define MAXN 1005 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct INT {int len, value[MAXL]; } a[MAXN]; INT operator + (INT a, INT b) { INT res; res.len = max(a.len, b.len); memset(res.value, 0, sizeof(res.value)); for (int i = 0; i <= res.len; i++) res.value[i] = a.value[i] + b.value[i]; for (int i = 0; i <= res.len; i++) { res.value[i + 1] += res.value[i] / 10; res.value[i] %= 10; } if (res.value[res.len + 1]) res.len++; return res; } INT operator - (INT a, INT b) { INT res; res.len = a.len; memset(res.value, 0, sizeof(res.value)); for (int i = 0; i <= res.len; i++) res.value[i] = a.value[i] - b.value[i]; for (int i = 0; i <= res.len; i++) if (res.value[i] < 0) { res.value[i] += 10; res.value[i + 1]--; } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT operator * (INT a, INT b) { INT res; res.len = a.len + b.len; for (int i = 0; i <= res.len; i++) res.value[i] = 0; for (int i = 1; i <= a.len; i++) for (int j = 1; j <= b.len; j++) res.value[i + j - 1] += a.value[i] * b.value[j]; for (int i = 0; i <= res.len; i++) { res.value[i + 1] += res.value[i] / 10; res.value[i] %= 10; } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT ten(int x) { INT res; res.len = x + 1; res.value[res.len] = 1; for (int i = 0; i < res.len; i++) res.value[i] = 0; return res; } bool operator >= (INT a, INT b) { if (a.len > b.len) return true; if (a.len < b.len) return false; for (int i = a.len; i >= 1; i--) { if (a.value[i] > b.value[i]) return true; if (a.value[i] < b.value[i]) return false; } return true; } INT operator / (INT a, INT b) { INT res, tmp; res.len = a.len - b.len + 1; for (int i = res.len; i >= 1; i--) { tmp = ten(i - 1) * b; while (a >= tmp) { res.value[i]++; a = a - tmp; } } while (res.len != 1 && res.value[res.len] == 0) res.len--; return res; } INT number(int x) { INT res; res.len = 0; if (x == 0) res.len = 1, res.value[1] = 0; memset(res.value, 0, sizeof(res.value)); while (x) { res.value[++res.len] = x % 10; x /= 10; } return res; } void print(INT x) { for (int i = x.len; i >= 1; i--) printf("%d", x.value[i]); printf("\n"); } int main() { int n; read(n); a[0] = number(1); for (int i = 1; i <= n; i++) a[i] = a[i - 1] * number(i); static INT tmp = number(1); int cnt = 0, lft = n - 2; for (int i = 1; i <= n; i++) { int x; read(x); if (x == 0 || x <= -2) { writeln(0); return 0; } if (x == -1) cnt++; else { x--; if (x > lft) { writeln(0); return 0; } lft -= x; tmp = tmp * a[x]; } } tmp = tmp * a[lft]; static INT ans = a[n - 2] / tmp; if (cnt == 0) tmp = number(1); else tmp = number(cnt); for (int i = 1; i <= lft; i++) ans = ans * tmp; print(ans); return 0; }
相关文章推荐
- [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】
- 【bzoj1005】[HNOI2008]明明的烦恼
- bzoj1005【hnoi2008】明明的烦恼
- bzoj1005 [HNOI2008]明明的烦恼 prufer+组合数学
- BZOJ 1005([HNOI2008]明明的烦恼-Prufer数列-树与数组的一一对应)
- BZOJ1005 [HNOI2008]明明的烦恼
- BZOJ 1005: [HNOI2008]明明的烦恼
- bzoj 1005: [HNOI2008]明明的烦恼(组合数学 purfer sequence)
- BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)
- bzoj1005 [HNOI2008]明明的烦恼(prufer序列+组合数学+高精)
- [BZOJ1005]HNOI2008 明明的烦恼|prufer编码|排列组合
- BZOJ1005: [HNOI2008]明明的烦恼
- [BZOJ]1005 明明的烦恼(HNOI2008)
- BZOJ 1005 [HNOI2008]明明的烦恼
- [BZOJ 1005][HNOI2008]明明的烦恼(prufer编码+组合数学+高精度)
- 【bzoj 1005】 明明的烦恼 【HNOI2008】
- 【BZOJ1005】【HNOI2008】明明的烦恼
- [bzoj 1005][HNOI 2008]明明的烦恼(prufer数列+排列组合)
- bzoj1005: [HNOI2008]明明的烦恼
- Bzoj1005 [HNOI2008]明明的烦恼