首页 > 代码库 > HDU3240-Counting Binary Trees(Catalan数+求逆元(非互质))

HDU3240-Counting Binary Trees(Catalan数+求逆元(非互质))

Counting Binary Trees

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 564    Accepted Submission(s): 184


Problem Description
There are 5 distinct binary trees of 3 nodes:

Let T(n) be the number of distinct non-empty binary trees of no more than n nodes, your task is to calculate T(n) mod m.
 

Input
The input contains at most 10 test cases. Each case contains two integers n and m (1 <= n <= 100,000, 1 <= m <= 109) on a single line. The input ends with n = m = 0.
 

Output
For each test case, print T(n) mod m.
 

Sample Input
3 100 4 10 0 0
 

Sample Output
8 2
 

Source
2009 “NIT Cup” National Invitational Contest
 
题意 求节点数小于n的二叉树的总和。
思路 递推公式: 设f(n)为节点数为n的二叉树的个数  f(n) = f(0)*f(n-1)+f(1)*f(n-2)+.....f(n-1)*f(0) (分成左子树和右子树)可以看出,该数列该Catalan数。
关键是还要对答案进行求模  考虑 Catalan数的递推公式  f(n) = (4*n-2)/(n+1) * f(n-1) ,有分母,因此要求逆元,但求逆元要保证两个数互质,因此可以先把m质因数分解,把分子中含有m的质因数保存起来,剩下的与m互质的直接求,分母中含有的质因数相应减去,剩下的如果大于1,那么直接求逆元,剩下的质因子就相应再乘上即可。
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 100000+10;
typedef long long ll;
ll ans;
ll cnt[maxn];
vector<int> prime;
int n,m;
void exgcd(ll a,ll b,ll& d,ll& x,ll& y) {
	if(!b) {
		d = a; x = 1; y = 0;
	}else{
		exgcd(b,a%b,d,y,x); y -= x*(a/b);
	}
}
ll inv(ll a,ll n){
	ll d,x,y;
	exgcd(a,n,d,x,y);
	return d== 1?(x+n)%n:-1;
}
void init(){
	prime.clear();
	memset(cnt,0,sizeof cnt);
}
void getPrime(){
	ll tmp = m;
	for(int i = 2; i*i <= tmp; i++){
		if(tmp%i==0){
			prime.push_back(i);
			while(tmp%i==0){
				tmp /= i;
			}
		}
	}
	if(tmp>1){
		prime.push_back(tmp);
	}
}
void solve(){
	getPrime();
	ans = 1;
	ll ret = 1;
	for(int i = 2; i <= n; i++){
		ll fz = 4*i-2,fm = i+1;
		for(int k = 0; k < prime.size(); k++){
			if(fz%prime[k]==0){
				while(fz%prime[k]==0){
					fz /= prime[k];
					cnt[k]++;
				}
			}
		}
		ret = (ret*fz)%m;
		for(int k = 0; k < prime.size(); k++){
			if(fm%prime[k]==0){
				while(fm%prime[k]==0){
					fm /= prime[k];
					cnt[k]--;
				}
			}
		}
		if(fm > 1){
			ret = (ret*inv(fm,m))%m;
		}
		ll tmp = ret;
		for(int k = 0; k < prime.size(); k++){
			for(int kk = 1; kk <= cnt[k]; kk++){
				tmp = (tmp*prime[k])%m; 
			}
		}
		ans = (ans+tmp)%m;
	}
	printf("%I64d\n",ans);
	
}
int main(){
	
	while(~scanf("%d%d",&n,&m) && n+m){
		init();
		solve();
	}
	return 0;
}


HDU3240-Counting Binary Trees(Catalan数+求逆元(非互质))