卡特兰数
模型
给定 n个 0 和 n 个 1,它们将按照某种顺序排成长度为 2n 的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列有多少个。
几何意义
对于每一个序列,我们定义
0:向右走一格
1:向左走一格
于是每一个长度为 2n 的序列都对应了坐标系中条从\((0, 0)\)走到\((n, n)\) 的路径
而所谓“任意前缀序列中 0 的个数都不少于 1 的个数”的几何意就是这些路径不能经过红色的点
于是我们所要求的序列就是,不经过红色点的,从\((0, 0)\)走到\((n, n)\) 的路径的数量
如何求?
正难则反——转换为,求“从\((0, 0)\)走到\((n, n)\) 的所有路径”的数量与“经过红色点的,从\((0, 0)\)走到\((n, n)\) 的路径"的数量的差。
从\((0, 0)\)走到\((n, n)\) 的所有路径”的数量
\[C_{2n}^{n} \]经过红色点的,从\((0, 0)\)走到\((n, n)\) 的路径"的数量
对于每一条这样的路径,我们总可以将第一个经过红色点的路径沿\(y = x\)翻折,于是所求就转换成了从\((0, 0)\)到\((n - 1, n + 1)\)的路径数量,类似于零点存在定理,这样的路径一定会经过红色的点,所以答案就是\(C^{n - 1}_{2n}\)
结论
于是不经过红色点的,从\((0, 0)\)走到\((n, n)\) 的路径的数量就是
\[C^{n}_{2n} - C^{n-1}_{2n} = \frac{1}{n + 1} C^{n}_{2n}\\ = \frac{2n (2n - 1)...(n+1)}{(n + 1)n !} \\ = \frac{2n (2n - 1)...n}{n !} \]代码
#include<iostream>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int qmi(int a, int k, int p){
int ans = 1;
while (k){
if (k & 1) ans = (ll) ans * a % p;
a = (ll)a * a % p;
k >>= 1;
}
return ans;
}
int main(void){
int n;
cin >> n;
int a = n * 2, b = n;
int ans = 1;
//求Ca-b
for (int i = a; i > a - b; i -- ) ans = (ll)ans * i % mod;
for (int i = 1; i <= b; i ++ ) ans = (ll)ans * qmi(i, mod - 2, mod) % mod;
//还有一个系数1 / (n + 1)
ans = (ll)ans * qmi(n + 1, mod - 2, mod) % mod;
cout << ans;
return 0;
}
标签:int,ll,路径,ans,序列,2n,卡特兰 来源: https://www.cnblogs.com/tsrigo/p/15726878.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。