hdu 5673 robot【默慈金数or卡特兰数】

补充知识:

  1. 卡特兰数
    • Catalan(n)=Cn2nn+1
    • Catalan(n)=4n2n+1Catalan(n1)
  2. 默慈金数
    • Mn=n/2i=0C2inCatalan(i)
    • Mn+1=Mn+n1i=0MiMn1i=(2n+3)Mn+3nMn1n+3
  3. 线性求解1~p-1mod p的逆元
    inv[i] = (p - p / i) * inv[p%i] % p。

详情参考:
默慈金数 http://blog.csdn.net/acdreamers/article/details/41213667
线性求逆元 http://blog.miskcoo.com/2014/09/linear-find-all-invert


题目大意:
机器人只能在原点及原点右侧,符合规定下可以选择左移一个、右移一个或原地不动,起点在原点,问有几种方式使机器人n次操作后回到原点,结果对1e9+7取余。

思路:

机器人最多走到n/2处;
在0-n/2中的i处,走到i在回到原点的方式有 C2inCatalan(i) 种;
因此 ans(n)=n/2i=0C2inCatalan(i)

也可以直接套默慈金数递推公式。

1.默慈金数代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const LL mod = 1e9 + 7;
const LL MAXN = 1e6 + 100;
LL inv[MAXN], m[MAXN];

int main(int argc, char const *argv[])
{
    inv[1] = 1;
    for(int i = 2; i < MAXN; i++)
        inv[i] = (mod - mod / i) * inv[mod % i] % mod; //预处理逆元
    m[1] = 1;
    m[2] = 2;
    for(int i = 3; i < MAXN; i++)  //默慈金数打表
    {
        m[i] = (2 * i + 1) * m[i-1] % mod + 3 * (i - 1) * m[i-2] % mod;
        m[i] = m[i] % mod * inv[i+2] % mod;
    }

    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        printf("%I64d\n", m[n]);
    }
    return 0;
}

2.catalan数

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const LL mod = 1e9 + 7;
const LL MAXN = 1e6 + 100;
LL inv[MAXN], c[MAXN], cat[MAXN];

int main(int argc, char const *argv[])
{
    inv[1] = 1;
    for(int i = 2; i < MAXN; i++)
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    cat[0] = 1;
    cat[1] = 1;
    for(int i = 2; i < MAXN; i++) //预处理卡特兰数
    {
        cat[i] = (4 * i - 2) * cat[i-1] % mod;
        cat[i] = cat[i] * inv[i+1] % mod;
    }

    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        c[0] = 1;
        for(int i = 1; i <= n; i++)  //c(n i)组合数
        {
            c[i] = (n - i + 1) * c[i-1] % mod;
            c[i] = c[i] * inv[i] % mod;
        }

        LL ans = 0;
        for(int i = 0; i <= n/2; i++)
        {
            ans += c[i<<1] * cat[i] % mod;
            ans %= mod;
        }
        printf("%I64d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值