卡特兰数 卡特兰前1000000项带mod
卡特兰数
1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452定义一:
C[0]=1
C[n+1]=C[0]*C[n]+C[1]*C[n-1]+C[2]*C[n-2]+...+C[n]*C[0]
定义二:
C[0]=1
C[n+1]=2(2n+1)/(n+2)*C[n]
应用:
1.括号化
矩阵连乘:P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(f(n-1)种)
2.出栈次序
一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?
3.类似问题 买票找零
有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
4.凸多边形三角划分
在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。比如当n=6时,f(6)=14。
5.一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
6.在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
7.给定N个节点,能构成多少种不同的二叉树?f(n)
8.对于在n位的2进制中,有m个0,其余为1的catalan数为:C(n,m)-C(n,m-1)。
9.有n个1和m个-1(n>m),共n+m个数排成一列,满足对所有0<=k<=n+m的前k个数的部分和Sk > 0的排列数。 问题等价为在一个格点阵列中,从(0,0)点走到(n,m)点且不经过对角线x==y的方法数(x>y)
考虑情况I:第一步走到(0,1),这样从(0,1)走到(n,m)无论如何也要经过x==y的点,这样的方法数为(( n+m-1,m-1 ));
考虑情况II:第一步走到(1,0),又有两种可能:
a . 不经过x==y的点;(所要求的情况)
b . 经过x==y的点,我们构造情况II.b和情况I的一一映射,说明II.b和I的方法数是一样的。设第一次经过x==y的点是(x1,y1),将(0,0)到(x1,y1)的路径沿对角线翻折,于是唯一对应情况I的一种路径;对于情况I的一条路径,假设其与对角线的第一个焦点是(x2,y2),将(0,0)和(x2,y2)之间的路径沿对角线翻折,唯一对应情况II.b的一条路径。
问题的解就是总的路径数 ((n+m, m)) - 情况I的路径数 - 情况II.b的路径数。
((n+m , m)) - 2*((n+m-1, m-1))
或:((n+m-1 , m)) - ((n+m-1 , m-1))
10.有n个1和m个-1(n>=m),共n+m个数排成一列,满足对所有0<=k<=n+m的前k个数的部分和Sk >= 0的排列数。(和问题1不同之处在于此处部分和可以为0,这也是更常见的情况) 问题等价为在一个格点阵列中,从(0,0)点走到(n,m)点且不穿过对角线x==y的方法数(可以走到x==y的点)。
把(n,m)点变换到(n+1,m)点,问题变成了问题1。
方法数为:
((n+m+1, m)) - 2*((n+m+1-1, m-1))
或:((n+m+1-1, m)) - ((n+m+1-1, m-1))
卡特兰前1000000项带mod
#include
#include
using namespace std;
#define LL long long
#define N 1000005
#define MOD 1000000007
long long ans[N];
void Egcd(LL a,LL b,LL &x,LL &y){ //扩展欧几里德
if(b==0){
x=1;
y=0;
return ;
}
Egcd(b,a%b,x,y);
LL tmp=x;
x=y;
y=tmp-a/b*y;
}
int main(){
int cas=0,n;
int i;
ans[0] = 0, ans[1] = 1;
for(i=2;i<=N;++i){
LL x,y;
Egcd(i+1,MOD,x,y); //求i+1的乘法逆元x
ans[i]=ans[i-1]*(4*i-2)%MOD*(x%MOD+MOD)%MOD;
}
while(scanf("%d",&n) && n!=-1){
printf("%lld\n",ans[n]);
}
return 0;
}