南邮 OJ 1218 标准2维表问题

标准2维表问题

时间限制(普通/Java) :  1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 183            测试通过 : 30 

比赛描述

设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

提示

 

题目来源

算法设计与实验题解



/* 成功打印 catalan[10000];
#include<iostream>
#define MAX_N 10001

int a[MAX_N][10001];		//a[i][j] 第 i 个 catalan 数的第 j 位
int len;

int main(){
	int i,j,temp;
	a[0][0] = a[1][0] = 1;
	len = 1;
	for(i=2;i<MAX_N;i++){
		for(j=0;j<len;j++){
			temp = a[i][j] + a[i-1][j]*(4*i-2);
			a[i][j+1] = temp/10;
			a[i][j] = temp%10;
		}
		while(a[i][len]){
			a[i][len+1] = a[i][len]/10;
			a[i][len] %= 10;
			len++;
		}
		for(j=len-1;j>0;j--){
			a[i][j-1] += a[i][j]%(i+1)*10;
			a[i][j] /= (i+1);
		}
		a[i][0] /= (i+1);
		while(!a[i][len-1]){
			len--;
		}
	}
	printf("catalen %d,len = :%d\n",MAX_N-1,len);
	for(j=len-1;j>=0;j--){
		printf("%d",a[MAX_N-1][j]);
	}
	printf("\n");
}
*/



/* Memory Limit Exceed
#include<iostream>
#define MAX_N 10001

int a[MAX_N][10001];		//a[i][j] 第 i 个 catalan 数的第 j 位
int len;

int main(){
	int i,j,temp,n;
	a[0][0] = a[1][0] = 1;
	len = 1;
	scanf("%d",&n);
	if(n==0||n==1){
		printf("1\n");
	}
	for(i=2;i<=n;i++){
		for(j=0;j<len;j++){
			temp = a[i][j] + a[i-1][j]*(4*i-2);
			a[i][j+1] = temp/10;
			a[i][j] = temp%10;
		}
		while(a[i][len]){
			a[i][len+1] = a[i][len]/10;
			a[i][len] %= 10;
			len++;
		}
		for(j=len-1;j>0;j--){
			a[i][j-1] += a[i][j]%(i+1)*10;
			a[i][j] /= (i+1);
		}
		a[i][0] /= (i+1);
		while(!a[i][len-1]){
			len--;
		}
	}
	for(j=len-1;j>=0;j--){
		printf("%d",a[n][j]);
	}
	printf("\n");
}
*/




/* 107MS
#include<iostream>
int a[10001];	
int len;

int main(){
	int i,j,temp,n;
	a[0] = 1;
	len = 1;
	scanf("%d",&n);
	if(n==0||n==1){
		printf("1\n");
		return 0;
	}
	for(i=2;i<=n;i++){
		for(j=0;j<len;j++){
			a[j] *= (4*i-2);
		}
		for(j=0;j<len;j++){
			a[j+1] += a[j]/10;
			a[j] %= 10;
		}
		while(a[len]){
			a[len+1] = a[len]/10;
			a[len] %= 10;
			len++;
		}
		for(j=len-1;j>0;j--){
			a[j-1] += a[j]%(i+1)*10;
			a[j] /= (i+1);
		}
		a[0] /= (i+1);
		while(!a[len-1]){
			len--;
		}
	}
	for(j=len-1;j>=0;j--){
		printf("%d",a[j]);
	}
	printf("\n");
}
*/


/* 10 MS
//catalan(n)=2n*(2n-1)*…(n+2)/n! 
//考虑n=1的特殊情况 catalan(n)=2n*(2n-1)*…(n+2)(n+1)/(n+1)! 
#include<iostream>

int getPrimes(int *p, int maxN){	//取得不大于maxN的所有素数,存放于数组p[]中,个数通过函数值返回
	bool *flag = new bool[maxN+1];
	int i,j,count;
	memset(p,0,maxN<<2);
	for(i=2;i<=maxN;i++){
		flag[i] = 1;
	}
	for(i=4;i<=maxN;i+=2){
		flag[i] = 0;
	}
	for(i=3;i<=maxN;i++){
		if(flag[i]){
			for(j=i<<1;j<=maxN;j+=i){
				flag[j] = 0;
			}
		}
	}
	count = 0;
	for(i=2;i<=maxN;i++){
		if(flag[i]){
			p[count++] = i;
		}
	}
	return count;
}

//将 first*(first+1)*……*last 的乘积,转换成素数的幂表示
//prime为素数表,primeNo为素数个数
void makeProductToPrimes(int first,int last,int *result,int *prime,int primeNo){
	int i,j,k;
	first--;
	memset(result,0,primeNo<<2);
	for(k=0;k<primeNo;k++){
		result[k] = 0;
		i = first;
		j = last;
		while(i!=j){
			i /= prime[k];
			j /= prime[k];
			result[k] += (j-i);
		}
	}
}

//prime[]:素数表
//primeNo:素数个数
//numerator[]:每个素数的幂
//result[]:转换成的结果
int primeToNum(int *prime, int primeNo, int *numerator, int *result, int maxLen){
	int i,j,k,len;
	memset(result,0,maxLen<<2);
	result[0] = 1;
	len = 1;
	for(i=0;i<primeNo;i++){
		for(j=0;j<numerator[i];j++){
			for(k=0;k<len;k++){
				result[k] *= prime[i];
			}
			for(k=0;k<len;k++){
				if(result[k]>10){
					result[k+1] += result[k]/10;
					result[k] %= 10;
				}
			}
			while(result[len]){
				result[len+1] = result[len]/10;
				result[len] %= 10;
				len++;
			}
		}
	}
	return len;
}

void printNum(int *p, int len){
	for(int i=len-1;i>=0;i--){
		printf("%d",p[i]);
	}
	printf("\n");
}

void catalan(int n){
	int primeNo,i,len;							//primeNo素数个数
	int *prime = new int[n<<1];					//不超过2n素数表
	primeNo = getPrimes(prime,n<<1);
	int *numerator = new int[primeNo];			//分子中每个素数的幂
	int *denominator = new int[primeNo];		//分母中每个素数的幂
	makeProductToPrimes(n+1,n<<1,numerator,prime,primeNo);
	makeProductToPrimes(1,n+1,denominator,prime,primeNo);
	for(i=0;i<primeNo;i++){
		numerator[i] -= denominator[i];
	}
	int *result = new int[n];
	len = primeToNum(prime,primeNo,numerator,result,n);
	printNum(result,len);
	delete[] result;
	delete[] denominator;
	delete[] numerator;
	delete[] prime;
}

int main(){
	int n;
	while(scanf("%d",&n)==1){
		catalan(n);
	}
}
*/



// 4 MS
#include<iostream>
#define LIMIT 10000					//大数相乘,每个int存放4位十进制数,太大的话会越界,太小的话处理会慢
int getPrimes(int *p, int maxN){	//取得不大于maxN的所有素数,存放于数组p[]中,个数通过函数值返回
	bool *flag = new bool[maxN+1];
	int i,j,count;
	memset(p,0,maxN<<2);
	for(i=2;i<=maxN;i++){
		flag[i] = 1;
	}
	for(i=4;i<=maxN;i+=2){
		flag[i] = 0;
	}
	for(i=3;i<=maxN;i++){
		if(flag[i]){
			for(j=i<<1;j<=maxN;j+=i){
				flag[j] = 0;
			}
		}
	}
	count = 0;
	for(i=2;i<=maxN;i++){
		if(flag[i]){
			p[count++] = i;
		}
	}
	return count;
}

//将 first*(first+1)*……*last 的乘积,转换成素数的幂表示
//prime为素数表,primeNo为素数个数
void makeProductToPrimes(int first,int last,int *result,int *prime,int primeNo){
	int i,j,k;
	first--;
	memset(result,0,primeNo<<2);
	for(k=0;k<primeNo;k++){
		result[k] = 0;
		i = first;
		j = last;
		while(i!=j){
			i /= prime[k];
			j /= prime[k];
			result[k] += (j-i);
		}
	}
}

//prime[]:素数表
//primeNo:素数个数
//numerator[]:每个素数的幂
//result[]:转换成的结果
int primeToNum(int *prime, int primeNo, int *numerator, int *result, int maxLen){
	int i,j,k,len;
	memset(result,0,maxLen<<2);
	result[0] = 1;
	len = 1;
	for(i=0;i<primeNo;i++){
		for(j=0;j<numerator[i];j++){
			for(k=0;k<len;k++){
				result[k] *= prime[i];
			}
			for(k=0;k<len;k++){
				if(result[k]>LIMIT){
					result[k+1] += result[k]/LIMIT;
					result[k] %= LIMIT;
				}
			}
			while(result[len]){
				result[len+1] = result[len]/LIMIT;
				result[len] %= LIMIT;
				len++;
			}
		}
	}
	return len;
}

void printNum(int *p, int len){
	int i,j;
	for(j=LIMIT/10;j;j/=10){
		if(p[len-1]%(j*10)/j){
			break;
		}
	}
	while(j){
		printf("%d",p[len-1]%(j*10)/j);
		j /= 10;
	}
	for(i=len-2;i>=0;i--){
		for(j=LIMIT/10;j;j/=10){
			printf("%d",p[i]%(j*10)/j);
		}
	}
	printf("\n");
}

void catalan(int n){
	int primeNo,i,len;							//primeNo素数个数
	int *prime = new int[n<<1];					//不超过2n素数表
	primeNo = getPrimes(prime,n<<1);
	int *numerator = new int[primeNo];			//分子中每个素数的幂
	int *denominator = new int[primeNo];		//分母中每个素数的幂
	makeProductToPrimes(n+1,n<<1,numerator,prime,primeNo);
	makeProductToPrimes(1,n+1,denominator,prime,primeNo);
	for(i=0;i<primeNo;i++){
		numerator[i] -= denominator[i];
	}
	int *result = new int[n];
	len = primeToNum(prime,primeNo,numerator,result,n);
	printNum(result,len);
	delete[] result;
	delete[] denominator;
	delete[] numerator;
	delete[] prime;
}

int main(){
	int n;
	while(scanf("%d",&n)==1){
		catalan(n);
	}
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值