[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 飞了,现在懒得删了。

posted @ 2016-08-06 11:59  xjr01  阅读(197)  评论(0编辑  收藏  举报