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;
}
时间: 2024-10-08 16:29:34

HDU3240-Counting Binary Trees(Catalan数+求逆元(非互质))的相关文章

FZU 1775 Counting Binary Trees 卡特兰数前n项和%m(m可为非素数

题目链接:点击打开链接 题意: 卡特兰数前n项和 结果%m 把答案当成2部分搞. #include<stdio.h> #include<cmath> #define int __int64 const int N = 100000; struct inverse_element{ int x, y, q; void extend_Eulid(int a,int b) { if(b == 0){ x = 1;y = 0;q = a; }else{ extend_Eulid(b,a%b

HDU 3240 Counting Binary Trees(组合数学-斯特林数,数论-整数快速幂,数论-求逆元)

Counting Binary Trees 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

【欧拉函数】(小于或等于n的数中与n互质的数的数目)

[欧拉函数] 在数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目.此函数以其首名研究者欧拉命名,它又称为Euler's totient function.φ函数.欧拉商数等. 例如φ(8)=4,因为1,3,5,7均和8互质. 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明. [证明]: 设A, B, C是跟m, n, mn互质的数的集,据中国剩余定理,A*B和C可建立一一对应的关系.因此φ(n)的值使用算术基本定理便知, 若 n= ∏p^(α(下标p))p|

(hdu step 2.1.6)找新朋友(欧拉函数的简单使用:求与n互质的元素的个数)

题目: 找新朋友 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2788 Accepted Submission(s): 1307   Problem Description 新年快到了,"猪头帮协会"准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大

UVA12493 - Stars(求1-N与N互质的个数)欧拉函数

Sample Input 3 4 5 18 36 360 2147483647 Sample Output 1 1 2 3 6 48 1073741823 题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3937 题目大意:圆上有N个点把圆分成N等分,求隔相同的点能一笔画完所有点的方法: 思考:要一笔画出,那么(N,K)必定没有在

HNU 12933 Random Walks Catalan数 阶乘求逆元新技能

一个Catalan数的题,打表对每个数都求一次逆元会T,于是问到了一种求阶乘逆元的打表新方法. 比如打一个1~n的阶乘的逆元的表,假如叫inv[n],可以先用费马小定理什么的求出inv[n],再用递推公式求出前面的项. 我们记数字 x 的逆元为f(x) (%MOD). 因为 n! = (n-1)! * n 所以 f(n!) = f( (n-1)! * n) = f( (n-1)! ) * f(n). 所以 f( (n-1)! ) = f(n!) * f( f(n) ) = f(n!) * n  

HDU-3240(卡特兰数+分解质因数后求逆元)

卡特兰数相关公式 : \(H_n = {C_{2n}^n \over n+1)}\) \(H_n = {(4n-2)\over n+1}\times H_{n-1}\) \(H_n = C_{2n}^n - C_{2n}^{n-1}\) $ H_n = \begin{cases} \sum_{i=1}^{n} H_{i-1} H_{n-i} & n \geq 2, n \in \mathbf{N_{+}}\ 1 & n = 0, 1 \end{cases} $ 因为 \(n\le 1000

UVA10303 - How Many Trees?(java大数+catalan数)

UVA10303 - How Many Trees?(java大数+catalan数) 题目链接 题目大意:给你1-N N个数,然后要求由这些数构成二叉搜索树,问有多少种这样的二叉搜索树. 解题思路:把前5项理出来,正好是1 2 5 14 42..就猜想是catalan数,结果也是对了.公式f(i + 1) = (4?i - 6)/ i; (i >= 2).结果很大,要用高精度. 代码: import java.util.*; import java.math.*; import java.io

【64测试20161112】【Catalan数】【数论】【扩展欧几里得】【逆】

Problem: n个人(偶数)排队,排两行,每一行的身高依次递增,且第二行的人的身高大于对应的第一行的人,问有多少种方案.mod 1e9+9 Solution: 这道题由1,2,5,14 应该想到Catalan数,但是我却花了两个小时去找递推式. 首先 Catalan数 : 基本规律:1,2,5,14,42,132,.......... 典型例题: 1.多边形分割.一个多边形分为若干个三角形有多少种分法. C(n)=∑(i=2...n-1)C(i)*C(n-i+1) 2.排队问题:转化为n个人