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