HDU1267——下沙的沙子有几粒(卡特兰&大数)

下沙的沙子有几粒?

题目描述: http://acm.hdu.edu.cn/showproblem.php?pid=1267
2005年11月份,我们学校参加了ACM/ICPC 亚洲赛区成都站的比赛,在这里,我们获得了历史性的突破,尽管只是一枚铜牌,但获奖那一刻的激动,也许将永远铭刻在我们几个人的心头。借此机会,特向去年为参加ACM亚洲赛而艰苦集训了近半年的各位老队员表示感谢。
实际上,除了获奖以外,在这次比赛期间还有一件事也让我们记忆深刻。那是比赛当天等待入场的时候,听到某个学校的一个队员在说:“有个学校的英文名很有意思,叫什么Hangzhou Dianzi University”. 哈哈,看来我们学校的英文名起的非常好,非常吸引人呀。
不过,事情的发展谁也没有料到,随着杭电英文校名的这一次曝光,影响越来越大,很多人开始对杭电英文校名进行研究,不久以后甚至还成立了一个专门的研究机构,叫做“HDU 校名研究会”。并不断有报道说-相-当-多的知名科学家改行,专门对该问题进行研究,学术界称之为“杭电现象”。很多人在国际知名期刊上发表了研究论文,这其中,尤以中国超级女科学家宇春小姐写的一篇研究报告最为著名,报告发表在science上,标题是“杭电为什么这样红?” 文中研究发现:Hangzhou Dianzi University这个校名具有深刻的哲学思想和内涵,她同时提出了一个大胆的猜想:“假定一个字符串由m个H和n个D组成,从左到右扫描该串,如果字符H的累计数总是不小于字符D的累计数,那么,满足条件的字符串总数就恰好和下沙的沙粒一样多。”
这就是当今著名的“宇春猜想”!
虽然还没能从数学上证明这个猜想的正确性,但据说美国方面在小布什的亲自干预下,已经用超级计算机验证了在(1<=n<=m<=1000000000000)时都是正确的。my god! 这是一个多么伟大的猜想!虽然我们以前总说,21世纪是属于中国的,可还是没想这一天来的这么早,自豪ing... + 感动ing...
感动和自豪之余,问题也来了,如果已知m和n的值,请计算下沙的沙粒到底有多少。

Ps:
1. 中国有关方面正在积极行动,着手为宇春小姐申报诺贝尔奖。
2、“宇春猜想”中提到的H和D组成的字符串现在被学术界成为“杭电串串”(“杭电串串”前不久被一个卖羊肉串的注册了商标,现在我校正在积极联系买断,据说卖方的底价是1000万欧元,绝不打折,看来希望不大,sigh...)

Input
输入数据包含多个测试实例,每个占一行,由两个整数m和n组成,m和 n 分别表示字符串中H和D的个数。由于我们目前所使用的微机和老美的超级计算机没法比,所以题目给定的数据范围是(1<=n<=m<=20)。

Output
对于每个测试实例,请输出下沙的沙粒到底有多少,计算规则请参考“宇春猜想”,每个实例的输出占一行。

Sample Input
   
   
   
   
1 1 3 1

Sample Output
   
   
   
   
1 3


其实与买票问题是相同的思想。买票问题的链接:http://blog.csdn.net/kay_zhyu/article/details/8718576。

不过这里没有全排的问题,所以总的公式是(m+n)!/(m!*n!*(m+1)),化简之后可以得到以下三种情况:

1、当n>1时,为(m+2)*....*(m+n)*(m-n+1)/n!

2、当n=1时,为(m-n+1)

3、当n=0时,为1。

这部分,加入了大数除法的函数。上一次偷懒不想写,这一次由于除数是一个大数,不得不写啦。

参考代码:

#include <stdio.h>
#include<string.h>
#include<stdlib.h>

#define M 10000
char str[M];
//算100以内的阶乘,存放在fact里面
char fact[41][M];

//用字符串表示大数,以'#'号结尾
//str1和str2是乘数,str是结果
int Mutiply(char *str1, char *str2, char *str)
{
	int i,j;
	int a,b;
	int Result[M];
	memset(Result,0,sizeof(Result));

	for(i = 0; str1[i] != '#'; ++i)
	{
		a = (int)(str1[i] - '0');
		for(j = 0; str2[j] != '#'; ++j)
		{
			b = (int)(str2[j] - '0');
			Result[i + j] += a * b;
		}
	}

	j += i - 1;
	i = 0;

	//到了最高位,如果不为零,就一直赋值。
	for(i = 0; (i < j || Result[i] > 0); ++i)
	{
		str[i] = Result[i] % 10 + '0';
		Result[i+1] += Result[i] / 10;
	}

	str[i] = '#';//加结束标志
	return i;
}

//除法的str1从0-n依次是高位到地位。故得到的str的结果也是一致的
int Divide(char *str1, int b, char* str)
{
	int i;
	int j;
	int carry = 0;
	int flag = 0;

	for(i = 0,j = 0; str1[i] != '#'; ++i)
	{
		carry = (str1[i] - '0') + carry * 10; 
		if(carry < b)
		{
			if(flag)
			{
				str[j++] = '0';
			}
			continue;
		}
		else
		{
			str[j++] = carry / b + '0';
			carry %= b;
			flag = 1;
		}
	}
	str[j] = '#';
	str[j + 1] = 0;
	return j;
}


//nLen表示所有字符的个数
void Invert(char *str, int nLen)
{
	int i;
	char temp;

	for(i = 0; i < (nLen >> 1); ++i)
	{
		temp = str[i];
		str[i] = str[nLen - i - 1];
		str[nLen - i - 1] = temp;
	}
}

void Print(char *str, int nLen)
{
	int i;
	for(i = 0; i < nLen; ++i)
	{
		putchar(str[i]);
	}
	printf("\n");
}



int Fact(int a)
{
	char buf[15];
	int nLen;
	fact[0][0] = '0';
	fact[1][0] = '1';
	fact[1][1]= '#';//记得加结束标志
	for(int i = 2; i <= a; ++i)
	{
		itoa(i,buf, 10);
		nLen = strlen(buf);
		buf[nLen] = '#';//记得加结束标志
		buf[nLen + 1] = 0;
		Invert(buf,nLen);
		nLen = Mutiply(fact[i - 1], buf, fact[i]);
		fact[i][nLen] = '#';//记得加结束标志
	}
	return nLen;
}

void main()
{
	int m,n;
	char buf[5];
	int i;
	int nLen;

	while(scanf("%d %d", &m,&n) != EOF)
	{
		if(n > m)
		{
			printf("0\n");
			continue;
		}
		else if(n == 0)
		{
			printf("1\n");
			continue;
		}

		itoa(m - n + 1,fact[m + 1], 10);//先把要成的(m-n+1)的因子放在fact[m+1]中
		nLen = strlen(fact[m + 1]);
		fact[m + 1][nLen] = '#';//记得加结束标志
		fact[m + 1][nLen + 1] = 0;
		Invert(fact[m + 1],nLen);

		for(i = 2; i <= n; ++i)
		{
			itoa(m + i,buf, 10);
			nLen = strlen(buf);
			buf[nLen] = '#';//记得加结束标志
			buf[nLen + 1] = 0;
			Invert(buf,nLen);
			nLen = Mutiply(fact[m + i - 1], buf, fact[m + i]);
			fact[i][nLen] = '#';//记得加结束标志
		}

		Invert(fact[m + n], nLen);//先反转之后再除

		for(i = 2; i <= n; ++i)
		{
			nLen = Divide(fact[m + n], i, str);
			memcpy(fact[m+n], str, (nLen + 2) * sizeof(char));
		}

		Print(fact[m+n], nLen);
	}
}



你可能感兴趣的:(HDU1267——下沙的沙子有几粒(卡特兰&大数))