[BZOJ1005][HNOI2008]明明的烦恼
[BZOJ1005][HNOI2008]明明的烦恼
试题描述
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
输入
第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
输出
一个整数,表示不同的满足要求的树的个数,无解输出0
输入示例
3 1 -1 -1
输出示例
2
数据规模及约定
见“输入”
题解
知道 prufer 序列这题就是删边题了。这题不仅要写高精度,还不能随便用除法,使劲压常数,组合数要分解质因数才能过!!
= =就当练高精度吧。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 1010 int n, deg[maxn], cnt; struct bign { int len, A[5010]; bign() { len = 1; memset(A, 0, sizeof(A)); } bign operator = (const int& t) { len = 1; A[0] = t; while(A[len-1] > 9) A[len] = A[len-1] / 10, A[len-1] %= 10, len++; return *this; } void clear() { for(; !A[len-1] && len; len--) ; if(!len) len = 1; return ; } bign operator * (const int& t) const { bign ans; ans.len = len; memcpy(ans.A, A, sizeof(A)); for(int i = 0; i < len; i++) ans.A[i] *= t; for(int i = 0; i < len; i++) ans.A[i+1] += ans.A[i] / 10, ans.A[i] %= 10; int j = len + 1; for(; ans.A[j-1] > 9;) ans.A[j] += ans.A[j-1] / 10, ans.A[j-1] %= 10, j++; ans.len = j; ans.clear(); return ans; } bign operator *= (const int& t) { *this = *this * t; return *this; } bign operator * (const bign& t) const { bign ans; ans.len = len + t.len - 1; for(int i = 0; i < len; i++) for(int j = 0; j < t.len; j++) ans.A[i+j] += A[i] * t.A[j]; for(int i = 0; i < ans.len; i++) ans.A[i+1] += ans.A[i] / 10, ans.A[i] %= 10; int j = ans.len + 1; for(; ans.A[j-1] > 9;) ans.A[j] += ans.A[j-1] / 10, ans.A[j-1] %= 10, j++; ans.len = j; ans.clear(); return ans; } bign operator *= (const bign& t) { *this = *this * t; return *this; } bign operator - (const bign& t) const { bign ans; ans.len = len; memcpy(ans.A, A, sizeof(A)); for(int i = 0; i < len; i++) { if(i < t.len) ans.A[i] -= t.A[i]; if(ans.A[i] < 0) ans.A[i] += 10, ans.A[i+1]--; } while(!ans.A[ans.len-1]) ans.len--; return ans; } bign operator -= (const bign &t) { *this = *this - t; return *this; } bign operator / (const bign& t) const { bign ans, f; f = 0; ans.len = -1; for(int i = len - 1; i >= 0; i--) { f *= 10; f.A[0] = A[i]; while(f >= t) { f -= t; ans.A[i]++; if(ans.len == -1) ans.len = i + 1; } } return ans; } bool operator >= (const bign& t) const { if(len != t.len) return len > t.len; for(int i = len - 1; i >= 0; i--) if(A[i] != t.A[i]) return A[i] > t.A[i]; return 1; } void print() { for(int i = len - 1; i >= 0; i--) putchar(A[i] + '0'); return ; } } ; int prime[maxn], cp; bool vis[maxn]; void prime_table() { for(int i = 2; i <= n; i++) { if(!vis[i]) prime[++cp] = i; for(int j = 1; j <= cp && i * prime[j] <= n; j++) { vis[i*prime[j]] = 1; if(i % prime[j] == 0) break; } } return ; } bign Pow(int a, int n) { bign sum, t; sum = 1; t = a; while(n) { if(n & 1) sum *= t; t *= t; n >>= 1; } return sum; } int Cp[maxn]; bign C(int n, int m) { for(int i = 1; i <= cp; i++) Cp[i] = 0; for(int i = n; i >= n - m + 1; i--) { int tmp = i; for(int j = 1; j <= cp; j++) if(tmp % prime[j] == 0) while(tmp % prime[j] == 0) Cp[j]++, tmp /= prime[j]; } for(int i = m; i; i--) { int tmp = i; for(int j = 1; j <= cp; j++) if(tmp % prime[j] == 0) while(tmp % prime[j] == 0) Cp[j]--, tmp /= prime[j]; } bign sum; sum = 1; for(int i = 1; i <= cp; i++) if(Cp[i]) sum *= Pow(prime[i], Cp[i]); return sum; } int main() { n = read(); prime_table(); int tot = 0; bool ok = 1; for(int i = 1; i <= n; i++) { int x = read(); if(x >= 0) deg[++cnt] = x - 1, tot += (x - 1); if(!x) ok = 0; } if(!ok || tot > n - 2) return puts("0"), 0; tot = n - 2; bign sum; sum = 1; for(int i = 1; i <= cnt; i++) { sum *= C(tot, deg[i]); tot -= deg[i]; } sum *= Pow(n - cnt, tot); sum.print(); putchar('\n'); return 0; }
除法的定义其实没用,我第一次用了除法 T 飞了,现在懒得删了。