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