HDU 3240 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.

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

卡特兰数+逆元

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const long long maxn = 100005;
long long f[maxn], p[maxn], P = 0, n, m, a[maxn], b[maxn], tot, sum[maxn], ans;

void prime()
{
	memset(f, 0, sizeof(f));
	for (long long i = 2; i < maxn; i++)
	{
		if (!f[i]) p[P++] = i;
		for (long long j = 0; j < P&&i * p[j] < maxn; j++)
		{
			f[i*p[j]] = 1;
			if (i%p[j] == 0) break;
		}
	}
}

void break_down(long long x)
{
	tot = 0;
	for (long long i = 0; i < P; i++)
	{
		if (x%p[i] == 0) a[tot++] = p[i];
		while (x % p[i] == 0) x /= p[i];
	}
}

/*long long inv(long long x, long long mod)
{
if (mod % x == 0) return x;
return inv(mod % x, mod)*(mod - mod / x) % mod;
}*/

void egcd(long long a, long long b, long long &x, long long &y)
{
	if (b == 0)
	{
		x = 1, y = 0;
		return;
	}
	egcd(b, a%b, x, y);

	long long t = x;
	x = y, y = t - a / b*y;

	return;
}

long long insert(long long x, long long y)
{
	for (long long i = 0; i < tot; i++)
	{
		while (x % a[i] == 0) b[i]++, x /= a[i];
		while (y % a[i] == 0) b[i]--, y /= a[i];
	}
	long long i, j;
	egcd(y, m, i, j);
	return x * i % m;
}

long long get()
{
	long long ans = 1;
	for (long long i = 0; i < tot; i++)
	for (long long j = 1; j <= b[i]; j++) (ans *= a[i]) %= m;
	return ans;
}

int main()
{
	prime();
	while (cin >> n >> m, n + m)
	{
		break_down(m);
		memset(b, 0, sizeof(b));
		memset(sum, 0, sizeof(sum));
		ans = 0;
		for (long long i = sum[0] = 1; i <= n; i++)
		{
			sum[i] = sum[i - 1] * insert(i * 4 - 2, i + 1) % m;
			(ans += sum[i] * get()) %= m;
		}
		cout << (ans + m) % m << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值