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

来源:互联网 发布:苹果电脑 音乐软件 编辑:程序博客网 时间:2024/05/21 12:41
机器人走方格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,ni; 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;}

原创粉丝点击