跳
【题目描述】
邪教喜欢在各种各样空间内跳。
现在,邪教来到了一个二维平面。
在这个平面内,如果邪教当前跳到了
(x,y)
,那么他下一步可以选择跳到以下
4
个点:
而每当邪教到达一个点,他需要耗费一些体力,假设到达 (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) 点花费的体力也需要被算入)。
由于答案可能很大,只需要输出答案对 109+7 取模的结果。
【输入描述】
读入两个整数
N
,
【输出描述】
输出仅一个整数,表示邪教需要花费的最小体力对 109+7 取模的结果。
【样例输入】
1 2
【样例输出】
6
【数据范围及提示】
对于
10%
的数据,满足
N
,
对于
30%
的数据,满足
N
,
对于 60% 的数据,满足 min(N,M)<=100 ;
对于 100% 的数据,满足 0<=N,M<=1012 , N⋅M<=1012 。
【Solution】
如图,我们画出平面的一部分:
假设我们的邪教要到图中黑色框的地方,将黑色框往上,左延伸,形成一个红色的长方形。
显然我们不能走回头路,所以我们要找的路径就是左上的
1
到 黑色框的最短路径。
显然,我们沿着红色框的长的一边走,走到走不了的时候就往黑色框走(这个我不会证明,但应该是正确的)。
根据杨辉三角形的性质,第
所以设邪教要到的点坐标为
ans=Min{[m mod p+C(n+m+1,n) mod p] mod p,[n mod p+C(n+m+1,m) mod p] mod p}
。
因为
n⋅m<=1012
,所以
n,m
中的最小值一定小于等于
106
。
所以我们可以用
Lucas
定理:
Cmn=Cm mod pn mod p⋅Cm/pn/p
,而
Cmn
又可以用逆元求。
Code
- #include <iostream>
- #include <cstdio>
- #define LL long long
- #define p 1000000007
- using namespace std;
- LL n,m;
- LL ans=0;
- LL power(LL x,LL y){
- if(y==0)return 1;
- if(y==1)return x;
- LL fx=power(x,y/2);
- if(y&1)return fx*fx%p*x%p;
- else return fx*fx%p;
- }
- LL C(LL x,LL y){
- if(x<y)return 0;
- if(y==0)return 1;
- LL ans=1;
- for(LL i=1;i<=y;i++){
- LL a=(x-i+1)%p;
- LL b=i%p;
- ans=ans*(a*power(b,p-2)%p)%p;
- }
- return ans;
- }
- LL Lucas(LL x,LL y){
- if(y==0)return 1;
- return Lucas(x/p,y/p)*C(x%p,y%p)%p;
- }
- int main(){
- cin>>n>>m;
- if(n<m){
- ans+=m%p+1;
- ans%=p;
- ans+=Lucas(n+m+1,n)%p-1;
- ans%=p;
- }
- else{
- ans+=n%p+1;
- ans+=Lucas(n+m+1,m)%p-1;
- ans%=p;
- }
- cout<<ans<<endl;
- return 0;
- }