zoukankan      html  css  js  c++  java
  • 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("
    ");
            scanf("%d",&n);
        }
        return 0;
    }
  • 相关阅读:
    银行家算法实例(转)
    DNS中的七大资源记录介绍!(转)
    android之存储篇_SQLite数据库_让你彻底学会SQLite的使用(转)
    回顾HTML5的语义化元素
    vueJs2.0学习笔记(六)
    vueJs2.0学习笔记(五)
    vueJs的学习笔记(四)
    vueJs2.0学习笔记(三)
    vueJs的学习笔记(二)
    vueJs 2.0学习笔记(一)
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673056.html
Copyright © 2011-2022 走看看