题意:
zzy今天刚买了两个水瓢
A
和
给出
思路:
我们首先先转化下这个问题。我们可以看做有这样一个长度为
2n
的01串,共有
n
个0和
哈哈,这个问题是不是看着有些眼熟。嗯,确实许多问题都可以转化成这个模型,例如能够匹配的括号数、在方格中不经过对角线从左上走到右下的种数、n个数的出栈次序,甚至是。。。n个节点的二叉树种类个数。最后一个虽然看起来没什么关系,但是他们确实是一个问题。
实际上这些问题都是卡特兰(Catalan)数的问题,现在我们就来推导下它的通项。
要求出满足要求的串的种类,我们可以用总的个数减掉不合格的种类个数。首先总的个数很容易求,在
2n
个位置挑选出
n
个位置填
那它又为什么和二叉树的形态个数等价呢?我们再来证明一下。首先我们设
f(n)
为
n
个结点的二叉树的形态个数,那么我们可以把它看成由根、
这只是一个不太好算的递推式,我们还要求出它的通项。
我们这里使用生成函数法,考虑函数
现在我们就得出了卡特兰数的通项了,也就可以直接解出该题的答案了。实际上,卡特兰数还有一个 O(n) 的递推公式 f(n+1)=4n−2n+1f(n) ,这个式子也经常的使用。
现在我们就可以愉快的解出这道题了。
贴个代码:
#include <cstdio>
typedef long long ll;
const int MAXN = 10000 + 100;
const ll MOD = 1000000007;
ll ans[MAXN];
ll extgcd(ll a, ll b, ll &x, ll &y){
ll d = a;
if(b == 0LL){
x = 1; y = 0;
}else{
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
}
return d;
}
ll mod_inverse(ll a, ll MOD){
ll x, y;
extgcd(a, MOD, x ,y);
return (x % MOD + MOD) % MOD;
}
void Init(){
ans[0] = ans[1] = 1;
for(int i = 2; i < MAXN; ++i){
ans[i] = (((ans[i - 1] * (4 * i - 2)) % MOD) * mod_inverse(i + 1, MOD)) % MOD;
}
return;
}
int main(int argc, char const *argv[]){
Init();
int x;
while(~scanf("%d", &x)){
printf("%lld\n", ans[x]);
}
return 0;
}