51Nod 1556 默慈金数(Motzkin numbers)

题目链接


题意:
有一个1*n的矩阵,固定第一个数为1,其他填正整数 ,且相邻数的差不能超过1,求方案数% 1 e 9 + 7 的结果。


思路:
显然:
如果第 i 个格子的数是1,则第 i + 1 个格子只有 1 或者 2 两种可能
而如果第 i 个格子的数不为1,则第 i + 1 个格子一定有三种可能。

则当考虑 1 n 矩阵填法的方案数时,如果我们已经知道了 1 ( n 1 ) 矩阵填法的方案数情况,假设:
A n s [ i ] 1 i 矩阵填法的总方案数
a [ i ] : 1 i 矩阵填完以后第 i 个格子的数是 1 的总方案数。

则: A n s [ n ] = 3 A n s [ n 1 ] a [ i ]
因为对于第 n 个格子填的数,如果第 n 1 个格子填数不为 1 ,则一定有三种情况,而当为第 n 1 个格子为 1 时,只有两种情况,减去即可。


故此时核心便在于求出每一个 a [ i ]

通过打表和面向 o e i s 编程的方法(滑稽),我们能发现a[i]数列有一个名字,叫作Motzkin numbers,中文翻译为:默慈金数,其具有一个重要递推式,为:

Mot[0] = Mot[1] = 1;
for i : 2 to n
    Mot[i] = ((2*i+1)*Mot[i-1] + 3*(i-1)*Mot[i-2])/(i+2)

故乘法逆元+递推可解。


代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;
const int A = 1e6 + 10;
ll Mot[A],Ans[A],inv[A],n;

void init(){
    inv[1] = 1;
    for(ll i=2 ;i<=n+2 ;i++){
        inv[i] = (mod - mod/i)*inv[mod%i]%mod;
    }
}

int main(){
    scanf("%I64d",&n);n--;
    init();

    Mot[0] = Mot[1] = 1;
    Ans[0] = 1;Ans[1] = 2;
    for(ll i=2 ;i<=n ;i++){
        Mot[i] = ((2*i+1)%mod*Mot[i-1]%mod + 3*(i-1)%mod*Mot[i-2]%mod)*inv[i+2]%mod;
        Ans[i] = (3*Ans[i-1]%mod - Mot[i-1])%mod;
    }
    if(Ans[n] < 0) Ans[n] += mod;
    printf("%I64d\n",Ans[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wubaizhe/article/details/80027591