hdu1131 Count the Trees (Catalan+高精乘完整版)

Problem Description

Another common social inability is known as ACM (Abnormally Compulsive Meditation). This psychological disorder is somewhat common among programmers. It can be described as the temporary (although frequent) loss of the faculty of speech when the whole power of the brain is applied to something extremely interesting or challenging.
Juan is a very gifted programmer, and has a severe case of ACM (he even participated in an ACM world championship a few months ago). Lately, his loved ones are worried about him, because he has found a new exciting problem to exercise his intellectual powers, and he has been speechless for several weeks now. The problem is the determination of the number of different labeled binary trees that can be built using exactly n different elements.

For example, given one element A, just one binary tree can be formed (using A as the root of the tree). With two elements, A and B, four different binary trees can be created, as shown in the figure.

If you are able to provide a solution for this problem, Juan will be able to talk again, and his friends and family will be forever grateful.

Input

The input will consist of several input cases, one per line. Each input case will be specified by the number n ( 1 ≤ n ≤ 100 ) of different elements that must be used to form the trees. A number 0 will mark the end of input and is not to be processed.

Output

For each input case print the number of binary trees that can be built using the n elements, followed by a newline character.

Sample Input
1
2
10
25
0

Sample Output
1
4
60949324800
75414671852339208296275849248768000000

Source

UVA

分析:
如果结点之间不区分,那么答案就是Catalan(n)
但是现在我们给每个结点都编上了编号
实际上就相当于在Catalan的基础上又乘上了一个全排列

最后答案就是:Catalan(n)*n!

tip

又是一道需要高精度的题
n<=100,所以我们可以先求出1~100的答案
之后O(1)输出就好了

这就启发我们:
如果数据范围较小,但是输出较多并且有较多重复
我们就可以考虑预处理出范围内的答案
最后O(1)输出

n=100的时候
答案是
83668813731927024711268882117380243222191749722895663025350640914710184372250456
81065763252100408384370875099755604477792721304918348893371737459906581789624186
1031582305812277285886602772480000000000000000000000000

数组不要开小了

写高乘低的时候,一定是大数每一位都乘较小的数

高乘高的

板子不要打错了

//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

int a[102][1002],jcc[102][1002];
int la[102],lj[102];

void mul(int u)
{
    int c[1002];
    memset(c,0,sizeof(c));
    int n=la[u]+lj[u];
    int len=max(la[u],lj[u]);
    for (int i=1;i<=len;i++)
    {
        int d=0;
        for (int j=1;j<=len;j++)
        {
            c[i+j-1]+=a[u][i]*jcc[u][j]+d;    //+=
            d=c[i+j-1]/10;
            c[i+j-1]%=10;
        }
        c[i+len]=d;
    }
    while (c[n]==0) n--;
    la[u]=n;
    for (int i=1;i<=n;i++) a[u][i]=c[i];
}

void catalan()
{
    la[1]=1; a[1][1]=1;
    int ll=1;
    for (int i=2;i<=100;i++)
    {
        int d=0;
        for (int j=1;j<=ll;j++)           //高乘低 
        {
            a[i][j]=a[i-1][j]*(4*i-2)+d;
            d=a[i][j]/10;
            a[i][j]%=10;
        }

        while (d)
        {
            a[i][++ll]=d;
            d=a[i][ll]/10;
            a[i][ll]%=10;
        }

        d=0;
        for (int j=ll;j>=1;j--)          //高除低
        {
            int t=d*10+a[i][j];
            a[i][j]=t/(i+1);
            d=t%(i+1);
        }

        while (a[i][ll]==0) ll--;
        la[i]=ll;
    }
}

void jc()
{
    lj[1]=1; jcc[1][1]=1;
    int ll=1;
    for (int i=2;i<=100;i++)
    {
        int d=0;
        for (int j=1;j<=ll;j++)
        {
            jcc[i][j]=jcc[i-1][j]*i+d;
            d=jcc[i][j]/10;
            jcc[i][j]%=10;
        }

        while (d)
        {
            jcc[i][++ll]=d;
            d=jcc[i][ll]/10;
            jcc[i][ll]%=10;
        }

        lj[i]=ll;
    }
}

int main()
{
    catalan();
    jc();
    for (int i=1;i<=100;i++)
        mul(i);
    int n;
    scanf("%d",&n);
    while (n)
    {
        for (int i=la[n];i>=1;i--)
            printf("%d",a[n][i]);
        printf("\n");
        scanf("%d",&n);
    }
    return 0;
}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673056.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值