[BZOJ 3260] 跳

Description

邪教喜欢在各种各样空间内跳。
现在,邪教来到了一个二维平面。在这个平面内,如果邪教当前跳到了      (x,y) ,
 
那么他下一步可以选择跳到以下 4个点: (x-1,y), (x+1,y), (x,y-1), (x,y+1)。
而每当邪教到达一个点,他需要耗费一些体力,假设到达      (x,y)需要耗费的体
 
力用 C(x,y)表示。   
 
对于 C(x,y),有以下几个性质:
1 、若x=0或者 y=0,则 C(x,y)=1。
 
2 、若x>0且 y>0,则 C(x,y)=C(x,y-1)+C(x-1,y)。
 
3 、若x<0且 y<0,则 C(x,y)=无穷大。
现在,邪教想知道从 (0,0)出发到(N,M),最少花费多少体力(到达        (0,0) 点花费的
 
体力也需要被算入)。  
由于答案可能很大,只需要输出答案对 10^9+7取模的结果。

Input

读入两个整数 N ,M,表示邪教想到达的点。 
 

Output

输出仅一个整数,表示邪教需要花费的最小体力对 10^9+7取模的结果。     

Sample Input


1 2

Sample Output

6

HINT

 

对于 100% 的数据,满足    0<=N, M<=10^12   ,N*M<=10^12。

 

 

题解:Lucas定理+贪心

先打出个表来,发现c数组就是杨辉三角嘛(只不过45°的放在数组里。

然后(x,y)的C值,就是组合数C(x+y,y)。

那么对于点n,m,先沿着(0,0)-->(1,0)-->(2.0)--...-->(n,0)

然后(n,1)-->(n,2)-->(n,3)--...(n,m),表上看出C(n,m)=C(m,n),(这个C是价值

然后用Lucas求组合数就可以啦。

其实本来想做费马小定理来着...

在Lucas求逆元中,n!/(m!*(n-m)!)==> n!*(m!*(n-m)在mod数意义下的逆元)

由欧拉定理知道a^(phi(n))≡1(mod n)当a,n互质时,费马小定理为当n为质数时

a^(phi(n))=a^(n-1)≡1(mod n),那么a关于MOD n意义下的逆元就是a^(n-2)。

假设n>m(让竖着走的1多一点

那么答案就是n+sigma(i=0--m)C(n+i,i)

sigma那个是  C(n+m+1,m)。

这个我不会证.....才怪 略略略

证明:C(n,0)+C(n+1,1)+C(n+2,2)+C(n+2,3)+....+C(n+m,m)

额...不会 推荐播客

代码:

最近Lucas定理做的太多了...不做了.... 感觉这个题的数据范围有点玄....

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const LL mod=1e9+7;

LL m,n;

LL ksm(LL x,LL y){
    LL ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}

LL C(LL n,LL m){
    if(m>n)return 0;
    LL s1=1,s2=1;
    for(LL i=n-m+1;i<=n;i++)s1=s1*i%mod;
    for(LL i=1;i<=m;i++)s2=s2*i%mod;
    return s1*ksm(s2,mod-2);
}

LL Lucas(LL n,LL m){
    if(!m)return 1;
    return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod; 
}

int main(){
    scanf("%lld%lld",&n,&m);
    printf("%lld\n",(max(n,m)%mod+Lucas(n+m+1,min(n,m))%mod)%mod);
    return 0;
}

 

 

 

 

posted @ 2017-10-15 09:31  ANhour  阅读(363)  评论(0编辑  收藏  举报