(赛前练手 #10)BZOJ1005 [HNOI2008]明明的烦恼(prufer数列 + 高精)

本文提供了一道HNOI2008竞赛题明明的烦恼的详细解析,该题涉及树的结构与度数约束。文章通过使用prufer数列与树的一一对应关系,结合排列组合的方法,解决如何在满足特定度数条件的情况下,生成不同树的问题,并提供了完整的AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1005: [HNOI2008]明明的烦恼
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 6664 Solved: 2626
[Submit][Status][Discuss]
Description
  自从明明学了树的结构,就对奇怪的树产生了兴趣…给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?

Input
  第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

Output
  一个整数,表示不同的满足要求的树的个数,无解输出0

Sample Input
3

1

-1

-1
Sample Output
2
HINT
  两棵树分别为1-2-3;1-3-2

Source

先粘一波其它博主的blog吧…
https://blog.youkuaiyun.com/jiangshibiao/article/details/22651081
其实我们还是利用prufer数列与树的一一对应关系,然后我们就可以利用排列组合来求了
AC Code:

#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 3000010
#define ll long long
#define eps 1e-8
using namespace std;
il int read(){rg int x = 0 , w = 1 ; rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') w = -1; ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0' ; ch = getchar();}return x * w;}
int q[maxn << 1] , tot , rnx[maxn] , a[maxn] , b[maxn] , c[maxn] , val[maxn] , primes[maxn];
int flag[maxn] , p[maxn] , delta;
bool vis[maxn];
void prime(int n){
	vis[1] = 1;
	for (rg int i = 2 ; i <= n ; ++i){
		if (!vis[i]) {
			primes[++tot] = i;
			rnx[i] = tot;
		}
		for (rg int j = 1 ; j <= tot && i * primes[j] <= n; ++j){
			vis[i * primes[j]] = 1;
			if (!(i % primes[j])) break;	
		}
	}	
}
void fenjie(int x){
	delta += p[x];
	rg int tmp = x , i = 1;
	if (!vis[x]){
		val[rnx[x]] += delta;
		return;
	}
	while (vis[tmp] && tmp != 1){
		while (!(tmp % primes[i])){
			val[i] += delta;
			tmp /= primes[i];
		}
		++i;
	}
	if (tmp != 1)
		val[rnx[tmp]] += delta;
}
int main(){
	prime(500000);
	int n = read() , x , res = 0 , cnt = 0 , sum = 0;
	for (rg int i = 1 ; i <= n ; ++i){
		x = read();
		if (x > 0){
			q[++cnt] = x;
			sum += x - 1;
		}
		else if (x == 0){
			puts("0");
			return 0;
		}
		else ++res;
	}
	if (sum > (2 * n - 2)){
		puts("0");
		return 0;	
	}
	rg int maxr = -1;
	maxr = max(maxr , n - 1);
	p[1]++;
	p[n - 1]--;
	p[1]--;
	p[n - 1 - sum]++;
	for (rg int i = 1 ; i <= cnt ; ++i){
		p[1]--;
		p[q[i]]++;
		maxr = max(q[i] , maxr);	
	}
	p[res] += n - 2 - sum;
	p[res + 1] -= n - 2 - sum;
	maxr = max(res + 1 , maxr);
	for (rg int i = 1 ; i <= 200005; ++i){
		fenjie(i);	
	}
	rg int len = 1;
	a[len] = 1;
	for (rg int i = 1 ; i <= 1000 ; ++i){
		if (!val[i]) continue;
		for (rg int j = 1 ; j <= val[i] ; ++j){
			int xx = primes[i];
			x = 0;
			for (rg int k = 1 ; k <= len ; ++k){
				a[k] = a[k] * xx + x;
				x = a[k] / 10;
				a[k] = a[k] % 10;
			}
			while(x > 0){
				a[++len] = x % 10;
				x /= 10;	
			}
		}
	}
	for (rg int i = len ; i >= 1 ; --i)
		printf("%d" , a[i]);
	return 0;
}	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值