1. 程式人生 > >[BZOJ 3260] 跳

[BZOJ 3260] 跳

return for -s define sigma script space scanf mod

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;
}

[BZOJ 3260] 跳