参考博客:ACdreamers.
事实上默慈金数很偏门,据说早就渗入ACM竞赛中了(庆幸我才初中)。
默慈金数定义:
在一个圆上有n个不同的点,画出彼此互不相交弦的方案数(可以不画)即是第n个默慈金数。
递推公式:
M(1)=1,M(2)=2
M(n+1)=M(n)+∑n−1i=0M(i)∗M(n−1−i)
神奇地可得:
M(n+1)=(2n+3)M(n)+3nM(n−1)n+3
转一下:
M(n)=(2n+1)M(n−2)+(3n−3)M(n−2)n+2
便于记忆的形式:
M(n)=(2(n−1)+3)M(n−2)+(3(n−2)+3)M(n−2)n+2
证明我可不会,当然我也不想会,记住吧。
那么这个东西有什么用呢?
不知道为什么,第n项的默慈金数等于以下的东西:
在一个格子图中,从(0,0)出发,走n步,每次可以往右、右下或右上走,不能走到y=0以下的地方,走到(n,0)的方案数。
这题和上面所讲的唯一不同的地方就是终点不一定是(n,0)。
这怎么办呢?
设 f(n) 表示n的答案。
假设现在走了n-1步,会停在0-n-1.
如果在(n-1,y)(y>0),则有三种走法,都是合法的。
如果在(n-1,0),则有两种走法,即向右上或向右,那么可以视作减去一个M(n-1).
所以 f(n)=f(n−1)∗3−M(n−1)
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]);
}