UVA - 1436 Counting heaps

Description

Download as PDF

We are given a rooted tree of n vertices. The vertices are to be labeled with numbers 1, 2,..., n so that each label is unique and the heap condition holds, i.e. the label of any vertex is less than the label of its parent. How many such labellings exist? Since this number may be quite large, calculate only its remainder modulo m .

Input 

The input contains several tree descriptions. The first line contains the number of input trees t(t$ \le$250) . Each tree description begins with a line containing the size of the tree n(1$ \le$n$ \le$500000) and an integer m(2$ \le$m$ \le$109) . n - 1 lines follow, i -th of which contains p(i + 1) , the number of the parent of the i + 1 -th vertex (1$ \le$p(i + 1)$ \le$i) . Vertex number 1 will be the root in each tree, so its parent will not be given. Total size of the input will not exceed 50MB.

Output 

For each tree output the number of its valid labellings modulo given m .


Explanation for sample: The 8 possible labellings from the last example test case are as follows:

\epsfbox{p4390.eps}

Sample Input 

4 
3 1000000
1 
1 
4 1000000
1 
1 
1 
5 1000000
1 
2 
3 
4 
5 1000000
1 
1 
3 
3

Sample Output 

2 
6 
1 
8
题意:给你一棵n个结点的有根树,要求给结点标号1~n,使得不同结点标号不同,且每个非根结点结点的标号比父结点小,求方案数。
思路:这题和UVA - 11174 Stand in a Line 是一样的,不过因为m不是素数,所以所以我们要把分子分母分解质因子,然后快速幂取模。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
typedef long long ll;
using namespace std;
const int maxn = 510005;

int pre[maxn], cnt[maxn];
int isleaf[maxn];
int prime[maxn], num_prime, cprime[maxn], isprime[maxn];

queue<int> q;
ll n, mod;

void init() {
	memset(isprime, 1, sizeof(isprime));
	num_prime = 0;
	int cnt = 0;
	isprime[0] = isprime[1] = 0;
	for (int i = 2; i < maxn; i++)
		if (isprime[i]) {
			isprime[i] = num_prime;
			prime[num_prime++] = i;
			for (int j = 2; j * i < maxn; j++)
				isprime[i * j] = 0;
		}
}

void bfs() {
	for (int i = 1; i <= n; i++)
		cnt[i] = 1;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		if (u == 1)
			continue;
		cnt[pre[u]] += cnt[u];
		isleaf[pre[u]]--;
		if (!isleaf[pre[u]])
			q.push(pre[u]);
	}
}

void fac(int a, int v) {
	for (int i = 0; a != 1; i++) {
		while (a % prime[i] == 0) {
			cprime[i] += v; 
			a /= prime[i];
		}
		if (isprime[a]) {
			cprime[isprime[a]] += v;
			break;
		}
	}
}

ll pow_mod(int a, int b) {
	ll x = a, tmp = 1;
	while (b) {
		if (b & 1)
			tmp = (tmp * x) % mod;
		b >>= 1;
		x = (x * x) % mod;
	}
	return tmp;
}

ll solve() {
	memset(cprime, 0, sizeof(cprime));
	for (int i = 2; i < n; i++)
		fac(i, 1);
	for (int i = 2; i <= n; i++)
		fac(cnt[i], -1);
	ll res = 1;
	for (int i = 0; i <= n && res != 0; i++)
		if (cprime[i]) 
			res = (res * pow_mod(prime[i], cprime[i])) % mod;
	return res;
}

int main() {
	init();
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%lld%lld", &n, &mod);
		pre[1] = -1;
		memset(isleaf, 0, sizeof(isleaf));
		for (int i = 2; i <= n; i++) {
			scanf("%d", &pre[i]);
			isleaf[pre[i]]++;
		}
		for (int i = 1; i <= n; i++)
			if (!isleaf[i])
				q.push(i);
		bfs();	
		printf("%lld\n", solve());
	}
	return 0;
}


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值