HDU3240-Counting Binary Trees(Catalan数+求逆元(非互质))

来源:互联网 发布:个人云计算 编辑:程序博客网 时间:2024/06/05 05:03

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 1004 100 0
 

Sample Output
82
 

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


0 0
原创粉丝点击