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.
![](https://i-blog.csdnimg.cn/blog_migrate/0b1e0fa4d5802f5ea0d5546f4947f7d6.jpeg)
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 <= 10
9) 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
Recommend
题目大意:
解题思路:问你不超过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;
}
版权声明:欢迎关注我的博客,本文为博主toyking原创文章,未经博主允许不得转载。