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.

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
题意
求节点数小于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;
}