51nod 1627 瞬间移动 组合数

来源:互联网 发布:股价历史数据库 编辑:程序博客网 时间:2024/05/18 06:40

有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n行第m列的格子有几种方案,答案对1000000007取模。


Input
单组测试数据。两个整数n,m(2<=n,m<=100000)
Output
一个整数表示答案。
Input示例
4 5
Output示例

10


这个图就是一个提示。我们从左上角只能调到蓝色部分,也就是说第一行和第一列都是不能用的,直接忽略。

最后一排和最后一列也是不能用的,因为只能往右下角走。

所以一共可供选择的只有n-2+m-2.也就是n+m-4个格子.

我们可以选取的也就是n-2或者m-2个,也就是求C(n+m-4,n-2) 或者C(n+m-4,m-2).

#include <iostream>#include <cstdio>#include <sstream>#include <set>#include <bitset> #include <queue> #include <stack> #include <list>#include <vector>#include <map>#include <string>#include <cstring>#include <cmath>#include <algorithm>usingnamespacestd;typedefset<int> Set;typedefvector<int> Vec;typedefset<int>::iterator It;typedeflonglong ll;#define mem(s,n) memset(s,n,sizeof(s))int p = 1000000007;ll quick_mod(ll a,ll b)//a^b%p 快速幂{ ll ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; }ll C(ll n,ll m)//nCm %p{if(n < m) return0; ll ans = 1;for(ll i=1;i<=m;i++) { ll a = (n - m + i) % p; ll b = i % p; ans = ans *(a * quick_mod(b,p-2) % p) % p;//逆元的知识}return ans;}ll Lucas(ll n,ll m)//Lucas定理{if(m == 0)return1;return C(n % p,m % p) * Lucas(n / p,m / p) % p;}int main(int argc, char *argv[]){ ll m,n,a,b; scanf("%lld%lld",&m,&n); b=m+n-4; a=min(m-2,n-2);printf("%lld\n",Lucas(b,a));return0;}