Train Problem II
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8378 Accepted Submission(s): 4477
1 2 3 10
1 2 5 16796题意:输入n,表示有n辆火车,求有几种出站方式。解题思路:这道题就是考伟大的卡特兰数,如果你还不了解这个神奇的数,那咱们就先来了解一下吧。=======================================================================
卡特兰数
卡特兰数又称卡塔兰数,是组合数学中一个常出现在各种计数问题中出现的数列。由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名。
卡特兰公式的应用很广泛,最典型的四种应用问题现描述如下:
1.括号化问题。 矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种) 2.出栈次序问题。
一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?
类似:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
3.将多边行划分为三角形问题。
将一个凸多边形区域分成三角形区域的方法数?
类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
4.给顶节点组成二叉树的问题。
给定N个节点,能构成多少种不同的二叉树?
Catalan数的解法
1.Catalan数的组合公式为 Cn=C(2n,n) / (n+1); 2.此数的递归公式为 h(n ) = h(n-1)*(4*n-2) / (n+1)。 令h(1)=1,h(0)=1,catalan数满足递归式: h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2) 例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2 h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(1)=1*2+1*1+2*1=5 另类递归式: h(n)=h(n-1)*(4*n-2)/(n+1); 该递推关系的解为: h(n)=C(2n,n)/(n+1) (n=1,2,3,...)
如果说这不够你塞牙缝,那就来看看这里吧点击填饱肚子
来,咱们回归正题,怎么解决这道题,中国人看问题一般最先看肯本问题,而解决这道题的根本就是大数的乘除运算:
大数运算,所谓大数,就是你都不知道它怎么读的数,比如10000的阶乘有3w多位,你应该是从前面读呢,还是从后面的个位数呢?
想想咱们平时怎么算乘除的,这里就是怎么算的:
假设用a[]数组来倒叙储存一个数(23存进去就是32),a[0]代表这个数的长度,a[1]是个位,a[2]是十位。。。现在开始算,假如用23*16,咱们先int yu=0,len=2,也就是余数现在是0,23的长度是2,先从个位算起,3*16 = 48, 那么算出来个位就是8,那怎么办呢,先给余数yu=4,再算2*16=32,然后32+yu=36,这时a[2]=6,那3怎么办呢,当然是给余数啦yu=3,由于已经乘完了那么3直接放到a[3]=3;得数就是a[3]a[2]a[1](368),别忘了a[0] = 3(长度);这就是神奇的乘法。
再想想咱们平时怎么算除法的:
假设用a[]存一个225(a[0]=3,a[1]=5,a[2]=2,a[3]=2),除数为25,现在开始算,int yu=0,len=3; 这次从数组a的最后一位算起,a[len]/25=0;那么a[len] = 0,然后把余数存进yu=2,再算下一位,(a[2]+10*yu)/25 = 0,a[len-1] = 0, yu = 22, (a[1]+10*yu)/25 = 9, a[1] = 9, yu = 0,这时a[3]=0,a[2]=0,a[1]=9,别忘了a[0]=1于是商=9;
好了看代码吧:
代码实现:
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 1000000+10; const int inf = -0x7fffffff; int a[maxn]; int pre[maxn]; int now[maxn]; int MAX; int main() { int m, n; while( ~scanf("%d%d",&m,&n) ) { memset(a,0,sizeof(a)); memset(pre,0,sizeof(pre)); memset(now,0,sizeof(now)); int i,j; for( i=1; i<=n; i++ ) scanf("%d",&a[i]); for( i=1; i<=m; i++ ) { MAX = inf; for( j=i; j<=n; j++ ) { now[j] = max(now[j-1]+a[j], pre[j-1]+a[j]); pre[j-1] = MAX; MAX = max(MAX, now[j]); } } printf("%d\n",MAX); } return 0; }