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 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
Recommend
zhonglihua | We have carefully selected several similar problems for you: 3249 3241 3242 3243 3244
题目大意:
问你不超过n个节点的二叉树的方案数,结果要对m求余。
解题思路:
方案数可以划分左右两边划分子问题也就是 h(n)=h(0)*h(n-1)+h(1)*(h-2)+..................+h(n-1)*h(0),一看就是卡特兰数,
关于卡特兰数必须要nlg^n的左右效率的算法解决
百度一下,知道:
令h(0)=1,h(1)=1,
catalan数满足:
递推式[1] :h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)
递推式[2] :h(n)=h(n-1)*(4*n-2)/(n+1);
递推式[3] :h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
递推式[4] :h(n)=c(2n,n)-c(2n,n+1)(n=0,1,2,...)
我们选择,递推式[2] :h(n)=h(n-1)*(4*n-2)/(n+1);
但是这个递推要求余,乘法求余没关系,除法要求逆元,除数有逆元的充要条件是 gcd(a,mod)==1,也就是除数与要模的那个数互质。
那么,我们对于mod分解因子,对于分母中的因子
(1)互质的数,分母直接求逆元
(2)不互质的数,无法求逆元,只能用分子去消。
解题代码:
#include <iostream> #include <cstdio> #include <map> #include <vector> #include <cstring> using namespace std; typedef long long ll; const int maxn=50; int tol,prime[maxn],cnt[maxn],n,mod; void getPrime(){ tol=0; int x=mod; for(int i=2;i*i<=x;i++){ if(x%i==0){ prime[tol++]=i; while(x%i==0) x/=i; } } if(x>1) prime[tol++]=x; } void extend_gcd(int a,int b,int &x,int &y){ if(b==0){ x=1; y=0; }else{ extend_gcd(b,a%b,x,y); int tmp=x; x=y; y=tmp-(a/b)*y; } } int inv(int a,int mod){ int x,y; extend_gcd(a,mod,x,y); return (x%mod+mod)%mod; } void deal1(ll &ret,int x){ for(int i=0;i<tol;i++){ while(x%prime[i]==0){ x/=prime[i]; cnt[i]++; } } ret=(ret*x)%mod; } void deal2(ll &ret,int x){ for(int i=0;i<tol;i++){ while(x%prime[i]==0){ x/=prime[i]; cnt[i]--; } } if(x>1){ int tmp=inv(x,mod); ret=(ret*tmp)%mod; } } ll pow_mod(ll a,ll b,ll p){ ll sum=1; while(b>0){ if(b&1) sum=(sum*a)%p; a=(a*a)%p; b/=2; } return sum%p; } void solve(){ ll ans=1,ret=1; memset(cnt,0,sizeof(cnt)); getPrime(); for(int i=2;i<=n;i++){ deal1(ret,4*i-2); deal2(ret,i+1); ll tmp=ret; for(int t=0;t<tol;t++){ tmp=( tmp*pow_mod(prime[t],cnt[t],mod) )%mod; } ans=(ans+tmp)%mod; } cout<<ans<<endl; } int main(){ while(cin>>n>>mod && (n||mod) ){ solve(); } return 0; }