默慈金数学习小记 && 51nod 1556 计算

来源:互联网 发布:findcontours源码实现 编辑:程序博客网 时间:2024/06/04 23:24

参考博客:ACdreamers.

事实上默慈金数很偏门,据说早就渗入ACM竞赛中了(庆幸我才初中)。

默慈金数定义:

在一个圆上有n个不同的点,画出彼此互不相交弦的方案数(可以不画)即是第n个默慈金数。

递推公式:
M(1)=1,M(2)=2
M(n+1)=M(n)+n1i=0M(i)M(n1i)
神奇地可得:
M(n+1)=(2n+3)M(n)+3nM(n1)n+
转一下:
M(n)=(2n+1)M(n2)+(3n3)M(n2)n+2
便于记忆的形式:
M(n)=(2(n1)+3)M(n2)+(3(n2)+3)M(n2)n+2

证明我可不会,当然我也不想会,记住吧。

那么这个东西有什么用呢?

不知道为什么,第n项的默慈金数等于以下的东西:
在一个格子图中,从(0,0)出发,走n步,每次可以往右、右下或右上走,不能走到y=0以下的地方,走到(n,0)的方案数。

51nod 1556 计算.

这题和上面所讲的唯一不同的地方就是终点不一定是(n,0)。

这怎么办呢?

f(n)表示n的答案。

假设现在走了n-1步,会停在0-n-1.

如果在(n-1,y)(y>0),则有三种走法,都是合法的。

如果在(n-1,0),则有两种走法,即向右上或向右,那么可以视作减去一个M(n-1).

所以f(n)=f(n1)3M(n1)

Code:

#include<cstdio> #define ll long long#define fo(i, x, y) for(ll i = x; i <= y; i ++)using namespace std;const ll mo = 1e9 + 7;ll ksm(ll x, ll y) {    ll s = 1;    for(; y; y >>= 1, x = x * x % mo)        if(y & 1) s = s * x % mo;    return s;}ll n, M[1000005], f[1000005];int main() {    scanf("%lld", &n);    M[1] = 1; M[2] = 2;    f[1] = 1; f[2] = 2;    fo(i, 3, n)        M[i] = ((2 * i + 1) * M[i - 1] + (3 * i - 3) * M[i - 2]) % mo * ksm(i + 2, mo - 2) % mo,        f[i] = (f[i - 1] * 3 - M[i - 2] + mo) % mo;    printf("%lld", f[n]);}