zoj3405 卡特兰数

Counting Factor Trees

Time Limit: 2 Seconds Memory Limit: 65536 KB

Factoring, i.e., listing all the prime factors, of an integer is a useful skill that often helps to solve math problems. For example, one of the ways to find the GCD (Greatest Common Divisor) or LCM (Least Common Multiple) of two integers is by listing all their prime factors. The GCD is then the product of all the common factors; the LCM is the product of all the remaining ones.

The Factor Tree is a tool for finding such prime factorizations. The figure below demonstrates three factor trees of 108. At the beginning a root with a number is given, say N, which is to be factored. Then, the root is factored into two children N1 and N2 such that N = N1 × N2 (N1 ≥ 2, N2 ≥ 2). Note that N1 and N2 need not be prime. The same factoring process continues until all the leaves are prime.

Three factor trees for 108

While the prime factorization is unique, the factor tree reflects the order in which the factors were found, and is by no means unique. So, how many factor trees of a number are there?

Input

There are no more than 10000 cases. A line containing an integer N (2 ≤ N ≤ 1000000000) is given for each case.

Output

Print the number of factor trees of N in a line for each case. The answer will be fit in a signed 64-bit integer.

Sample Input
12
108
642485760
Sample Output
6
140
9637611984000


题意:给一个数n,然后分解它的质因子,再用它的质因子重新组合成树,叶子结点(图片上绿色的部分)都为质因子,问能够组成多少颗不同的树

思路:根据题目可以立马想到n=pi^r1*p2^r2……pm^rm,然后主要要求的是两部分,一部分是叶子从左往右的排列组合方案,第二部分是树的形态。

第一部分:ans1=C(r1,r1)*C(r1+r2,r2)*……C(r1+r2+……rm,rm)。太久没用过排列组合有些生疏了想了很久才明白,如果考虑两个数n个A,m个B,先放A,在m+n个位置中选取n个位置放A,然后B直接放,答案就是C(m+n,n)。而到多的数的时候,不过是利用前面求得的进行递推

第二部分:f(n)=f(1)*f(n-1)+f(2)*f(n-2)……+f(n-1)*f(1),一开始也是不知道这是卡特兰数,找了下卡特兰数的专题看后才知道,等式中f(1)*f(n-1)是总共有n个结点,然后根的左边有1个叶子结点,右边有n-1个叶子结点。其中f(1)=f(2)=1,f(3)=2,f(4)=5,从而推断出等于卡特兰数h(n-1),这里n为结点数。因为这道题本来就要求C(n,m)所以干脆都打好表,h(n)也等于C(2n,n)/(n+1)

因为n范围在一亿以内,因子数最多不超过31个,因为int最多不过2^31,所以卡特兰数求31以内的足够了,C由于要算C(2n,n)所以至少要算到C[62][62]。素数表打个√n就够了,40000差不多,全部弄完跑了30ms,我本来用map记录已找过的结果反而跑了40ms尼玛= =

#include<cstdio>
#include<cstring>
int prime[40000],tp;
bool isprime[40000];
long long C[85][85];
long long Catalan[45];
void init(){
	memset(isprime,false,sizeof(isprime));
	memset(C,0,sizeof(C));
	memset(Catalan,0,sizeof(Catalan));
	tp=0;
	for(int i=2;i<=35000;i++){
		if(!isprime[i]){
			prime[tp++]=i;
			for(int j=i+i;j<=35000;j+=i)
				isprime[j]=true;
		}
	}
	C[0][0]=1;
	for(int i=1;i<=66;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j-1]+C[i-1][j];
	}
	for(int i=0;i<=33;i++)
		Catalan[i]=C[2*i][i]/(i+1);
}
long long slove(int n){
	int sum=0;
	int cou;
	int temp=n;
	long long ans=1;
	for(int i=0;i<tp&&prime[i]*prime[i]<=n;i++)
		if(n%prime[i]==0){
			cou=0;
			do{
				n/=prime[i];
				cou++;
			}while(n%prime[i]==0);
			sum+=cou;
			ans*=C[sum][cou];
		}
	if(n!=1)
		sum++,ans*=C[sum][1];
	ans*=Catalan[sum-1];
	return ans;
}
int main(void){
	init();
	int n;
	while(~scanf("%d",&n)){
		printf("%lld\n",slove(n));
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值