2017-10-22 51nod 1120 卢卡斯定理 Lucas 组合数取模 卡特兰数

机器人走方格V3

前情提要:因为我要跨过长江去比赛了,但是我这人着实很水(差不多是凑数被拉过去的),又不想要拉两位大佬太多后腿(其实一定要说的话我比较擅长奇怪的水题噗嗤),所以我觉得我怎么说要把以前的东西捡一捡,好几个月没写题了,从头开始复习一波好了.今天是之前写过的走方格的后续(脸上笑嘻嘻,内心MmP)(怎么又是机器人 妈呀)

题目描述:N * N的方格,从左上到右下画一条线。一个机器人从左上走到右下,只能向右或向下走。并要求只能在这条线的上面或下面走,不能穿越这条线,有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10007的结果。

Input:输入一个数N(2 <= N <= 10^9)。

Output: 输出走法的数量 Mod 10007。

Sample Input:

4

Sample Output:

10

什么叫做没有学过的吃亏?这就是

虽然比较厉害的人能找到规律用组合数来表示答案,但是我不行>>>>>>>>

那还能说啥啊老老实实百度啊,然后说是卡特兰数,然后我在大二拿到的离散数学的课本里面看见了卡特兰数............

那么这里就不详细介绍卡特兰数啦,书上/百科/问人/下面的代码都能看出来是多少

鉴于这个也是约定俗成一组数列,可以像斐波那契数列一样把前面几个数字给记住,这样子眼熟一下比较好

(卡特兰数前10项:1,1,2,5,14,42,132,429,1430,4862.作者爱记不记,嗯

已知卡特兰数是用组合数表示的,那么势必会用到求(大)组合数(可能还要取个模)

这里引入一个可处理10^5级别的求组合数的定理,卢卡斯定理(Lucas定理)

先贴一个网址:pi9nc/article/details/9615359

(是同站的一篇文章,上面有一些说明可以作为学习或者回忆的引子,另一个地方是wiki(不得不说这些东西在维基上都有不错的证明和说明,有机会一定要多看看)

先贴代码:

#include <stdio.h>
#include <stdlib.h>
#define MOD 10007
long long int quick_mod(long long int a,long long int p,long long int mod)
//计算(a^p)%mod即快速幂 用于计算指数p特别大的情况
{
    //计算(a^p)%mod
    long long int res=1;
    while(p)
    {
        if(p&1)
            res=res*a%mod;//int有可能会冒,视情况换成long long(这里换了)
        p>>=1;//就是 p=p/2
        a=(a*a)%mod;
    }
    return res;
}

long long int cn(long long int m,long long int n,int p)
//从n个里面选m个
{
    long long int res,up,down;
    int i;
    if(m>n)
        return 0;
    else if(m==n)
        return 1;
    if(n-m<m) m=n-m;
    up=down=1;
    for(i=0;i<m;i++)
    {
        up=(up*(n-i))%p;
        down=(down*(m-i))%p;
    }
    //printf("%lld %lld\n",up,down);
    res=(up*quick_mod(down,p-2,p))%p;
    return res;
    
}

long long int LUCAS(long long int m,long long int n,int p)
{//适用于p不大的情况
    //这里的m和n的意思是从n个里面选m个
    long long int res,mm,nn;
    res=1;
    mm=m;
    nn=n;
    while(mm&&nn&&res)
    {//这个循环可以说是卢卡斯定理体现的地方
        res=(res*cn(mm%p,nn%p,p))%p; nn=nn/p; mm=mm/p;
    }
    return res;
    
}
int main()
{
    long long int res1,res2,res,n;
    while(scanf("%lld",&n)!=EOF)
    {
        n--;
        res1=LUCAS(n,2*n,MOD);
        res2=LUCAS(n-1,2*n,MOD);
        res=(2*(res1-res2)%10007+10007)%10007;//卡特兰数的组合数表示形式,具体的以后上离散数学课可能要学
        printf("%lld\n",res);
    }
    return 0;
}


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值