catalan 数 标准二维表。 高精度计算。

博客通过示例解释了如何计算2xn标准2维表的Catalan数,使用递推方法解决高精度问题。当数据规模较大时,由于效率问题,提出了使用质因数分解简化计算的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

设n 是一个正整数。2xn的标准2维表是由正整数1,2,…,2n 组成的2xn 数组,该数组的每行从左到右递增,每列从上到下递增。2xn的标准2维表全体记为Tab(n)。例如,当n=3时Tab(3)如下:

给定正整数n,计算Tab(n)中2´n的标准2 维表的个数。

输入

输入的第一行有1个正整数n 

输出

输出计算出的Tab(n)中2xn的标准2维表的个数 

样例输入

3

样例输出

5


将数字从1..2n 排序,依次插入二维表, 因为每一列升序排序,那么插入第一行可以看作是入栈操作, 插入第二行可以看做出栈操作, 标准二维表的数量符合catalan数。 


高精度求catalan数函数:

void catalan() //求卡特兰数
{
    int i, j, len, carry, temp;
    a[1][0] = b[1] = 1;
    len = 1;
    for(i = 2; i <= 100; i++)
    {
        for(j = 0; j < len; j++) //乘法
        a[i][j] = a[i-1][j]*(4*(i-1)+2);
        carry = 0;
        for(j = 0; j < len; j++) //处理相乘结果
        {
            temp = a[i][j] + carry;
            a[i][j] = temp % 10;
            carry = temp / 10;
        }
        while(carry) //进位处理
        {
            a[i][len++] = carry % 10;
            carry /= 10;
        }
        carry = 0;
        for(j = len-1; j >= 0; j--) //除法
        {
            temp = carry*10 + a[i][j];
            a[i][j] = temp/(i+1);
            carry = temp%(i+1);
        }
        while(!a[i][len-1]) //高位零处理
        len --;
        b[i] = len;
    }
}

 a[i][j]  保存i对应的卡特兰数的倒数第j 位。


但是此题隐藏的数据规模为10000 。 那么便无法建立a[][]这个二维数组, 只能牺牲效率,采用递推的方法计算输入的每一个n。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
int a[10001] = {0};
int aa[10001]={0};
int main()
{
    int n,i,j,len,r,temp,t;
    int b[10001];
cin>>n; 
 
  //  a[1][0] = 1; // ??????????????????????????????
aa[0]=1;
    len = 1;
    b[1] = 1;
    for (i = 2; i <= n; i++)
    {
        t = i - 1;
       for (j=0;j<len;j++) // ????????????,???????????????


   {
   // a[i][j] = a[i-1][j] * (4 * t + 2);
  a[j]=aa[j]* (4 * t + 2);
   }
        for (r = j = 0; j < len; j++) // ??????????????????
        {
           // temp = a[i][j] + r;
temp = a[j] + r;


           // a[i][j] = temp % 10;
a[j] = temp % 10;
            r = temp / 10;
        }
        while (r) // ????????????


        {
          //  a[i][len++] = r % 10;
a[len++] = r % 10;
            r /= 10;
        }
        for (j = len-1, r = 0; j >= 0; j--) // ??????????????????????????????
        {
           // temp = r * 10 + a[i][j];
temp = r * 10 + a[j];
          //  a[i][j] = temp / (t+2);
a[j] = temp / (t+2);
            r = temp % (t+2);
        }
       while (!a[len-1]) // ???????????????
   {
    len--;
   }
        b[i] = len; // ?????????????????????
for(j=0;j<len;j++)
aa[j]=a[j];
     }
for(j = b[n] - 1; j >= 0; j--)
   {
    printf("%d",aa[j]);
   }
        printf("\n");
    

       
    
    return 0;
}


明显效率很低。


对于catalan数 C(n,2n)/(n+1)

可以分解为质因子相乘的形式。 那么乘法和除法可以简化为质因子指数的加减。

#include "iostream"
#define CARRYS 10000


int  prmStatic(int *prm,int num)  // 产生小于num的所有质数。
{
    int total=0,i=2,j;
    int *judge = new int[num+1];
    for(j=1;j<=num;j++)
      judge[j]=j;             
    while(i<num+1)                           
    {
        while(!judge[i]) i++; 
prm[total]=i;
        total++;
        for(j=i;j<num+1;j+=i)
            judge[j]=0;
    }
return total;
}
void breakNum(int left,int right,int *prm,int *stat)  //质因数分解
{
    int k,m,n,t;
    k=m=right,n=left,t=0;
     while(prm[t]<=k)
    {
           while(left!=right)
          {
             left/=prm[t];
             right/=prm[t];
             stat[t] += (right-left);
          }
          t++;
          right=m;
          left=n;
    }
}
void carryPro(int *poly, int carry, int total, int &curpos)
{
poly[curpos] += carry;
int i = poly[curpos]/CARRYS;
if((curpos<total)||carry)
{
poly[curpos]%= CARRYS;
curpos++;
carryPro(poly, i, total, curpos);
}
}
void mulAll(int&m,int *prm, int *result, int prmsum, int *Last)
//累乘
{

Last[0] = 1,m=1;
for(int i=0; i<prmsum; i++)
{
for(int t=0; t<result[i]; t++)
{
for(int k=0; k<m; k++)
 Last[k] *= prm[i];
for(int j=0; j<m; j++)
 if(Last[j]>=CARRYS)
  {
int k = j+1;
carryPro(Last, Last[j]/CARRYS, m, k);
Last[j] %= CARRYS;
if(m<k+1) m = k+1; 
break;
  }
}
for(int j=m-1; j>=0; j--)
{
  if(Last[j]!=0) break;
  m--;
}
}
}




void Print(int polysum, int *last)
//输出结果
{
printf("%d",last[polysum-1]);
for(int i=polysum-2; i>=0; i--)
{
int j;
            for (j=CARRYS/10;j;j/=10)
printf("%d",last[i]/j%10);
}
}


int main(){
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       int m,presum=0;
scanf("%d",&m);
int *prm = new int[m];
int *last = new int[1500];
memset(prm, 0, 4*m);
presum=prmStatic(prm,m*2);
int *mole = new int[presum];
       int *denom = new int[presum];
       memset(denom, 0, 4*presum);
memset(mole, 0, 4*presum);
       breakNum(1, m+1,prm, denom);
       breakNum(m, 2*m,prm, mole); 
for(int i=0; i<presum; i++)
   mole[i] = mole[i]-denom[i]; 
       memset(last,0,6000);     
mulAll(m,prm, mole, presum, last);
Print(m ,last);
delete []mole;
delete []prm;
delete []last;
       return 0;
}

nTab(n)=2n*(2n-1)*…(n+2)/n!
nTab(n)=2n*(2n-1)*…(n+2)/n!
nTab(n)=2n*(2n-1)*…(n+2)/n!
nTab(n)=2n*(2n-1)*…(n+2)/n!
nTab(n)=2n*(2n-1)*…(n+2)/n!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值