1. 程式人生 > >BZOJ3260 跳 【組合數】

BZOJ3260 跳 【組合數】

code edge 題目 答案 define cst sin 當前 選擇

題目

邪教喜歡在各種各樣空間內跳。現在,邪教來到了一個二維平面。
在這個平面內,如果邪教當前跳到了(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取模的結果。

輸入格式

讀入兩個整數 N ,M,表示邪教想到達的點。
0<=N, M<=10^12 ,N*M<=10^12

輸出格式

輸出僅一個整數,表示邪教需要花費的最小體力對 10^9+7取模的結果。

輸入樣例

1 2

輸出樣例

6

題解

畫一下圖就發現是一個楊輝三角

先使\(M \le N\)
我們要走到\({N + M \choose M}\)
貪心一下路徑就是先走\(N + 1\)\(1\),再斜著走\(M\)
嘗試改變一下路徑就發現這樣的貪心沒有問題

答案就是
\[N + \sum\limits_{i = 0}^{M} {N + i \choose i}\]
組合數有一個比較常用的結論就是
\[\sum\limits_{i = 0}^{M} {N + i \choose i} = {N + M + 1 \choose M}\]


由組合數遞推可證明

那麽答案就是
\[N + {N + M + 1 \choose M}\]
由於題目有\(N*M \le 10^{12}\)的限制,所以\(M \le 10^6\),直接算就好了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts(""); using namespace std; const int maxn = 100005,maxm = 100005,INF = 1000000000,P = 1e9 + 7; LL N,M; LL qpow(LL a,LL b){ LL ans = 1; for (; b; b >>= 1,a = a * a % P) if (b & 1) ans = ans * a % P; return ans; } int main(){ scanf("%lld%lld",&N,&M); if (M > N) swap(N,M); LL ans = 1,ansb = 1; for (LL i = 1; i <= M; i++){ ans = ans * ((N + M + 2 - i + P) % P) % P; ansb = ansb * i % P; } ans = ((ans * qpow(ansb,P - 2) % P + N) % P + P) % P; printf("%lld\n",ans); return 0; }

BZOJ3260 跳 【組合數】