描述
设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;
}