Counting Binary Trees
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 660 Accepted Submission(s): 213
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
题意:1-n个点构成的二叉树的数目的和%m的结果。
思路:n个点构成的二叉树数目就是n的卡特兰数。其递推公式为dp[i]=dp[i-1]*(i*4-2)/(i+1)。我们首先将m分解质因子,然后对于乘数和除数其与m互质的部分直接乘和做逆元,不互质的部分记录每个质因子各有多少没有乘进去,然后最后一一乘完取模即可。
AC代码如下:
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int n;
ll m,prime[10010],num[10010],ans;
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
d=a;
}
else
{
ex_gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
ll inv(ll a,ll m)
{
ll d,x,y;
ex_gcd(a,m,d,x,y);
return d==1 ? (x+m)%m : -1;
}
void solve1(ll x)
{
int i,j,k;
for(i=1;i<=prime[0];i++)
while(x%prime[i]==0)
{
num[i]++;
x/=prime[i];
}
ans=ans*x%m;
}
void solve2(ll x)
{
int i,j,k;
for(i=1;i<=prime[0];i++)
while(x%prime[i]==0)
{
num[i]--;
x/=prime[i];
}
ans=ans*inv(x,m)%m;
}
int main()
{
int i,j,k;
ll ret,temp;
while(~scanf("%d%I64d",&n,&m) && n+m)
{
prime[0]=0;
ret=m;
for(i=2;i*i<=ret;i++)
if(ret%i==0)
{
prime[++prime[0]]=i;
while(ret%i==0)
ret/=i;
}
if(ret>1)
prime[++prime[0]]=ret;
memset(num,0,sizeof(num));
ans=1;ret=1;
for(i=2;i<=n;i++)
{
solve1(4*i-2);
solve2(i+1);
temp=ans;
for(j=1;j<=prime[0];j++)
for(k=1;k<=num[j];k++)
temp=temp*prime[j]%m;
ret=(ret+temp)%m;
}
printf("%I64d\n",ret);
}
}