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; }