瞬间移动
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 893 Accepted Submission(s): 476
Problem Description
有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n行第m列的格子有几种方案,答案对1000000007取模。
Input
多组测试数据。
两个整数n,m(2≤n,m≤100000)
Output
一个整数表示答案
Sample Input
4 5
Sample Output
10
Source
2016”百度之星” - 初赛(Astar Round2B)
首先找出是一个杨辉三角。。。
那么很容易得到 ans = C (m+n-4,m-2)
然后的话组合数取模,但是mod太大,这时候有三种方法:
- 预处理阶乘,然后直接定义法求解
- 预处理N以内的逆元,然后用组合数线性递推公式边走边求
- 直接求出阶乘,然后用递归求逆元,此时的数可能超过N
下面给出第一种方法,注意阶乘要预处理到2N,因为是m+n-4数量级的。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
const int INF=0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 200005;
const int N = 200000;
int fac[maxn];
int quick_exp(int a,int p)
{
if(!p) return 1;
if(p==1) return a%mod;
int tmp=quick_exp(a,p>>1);
tmp=(LL)tmp*tmp%mod;
if(p&1) return (LL)tmp*a%mod;
else return tmp;
}
int C(int m,int n)
{
int tmp=(LL)fac[m]*quick_exp(fac[n],mod-2)%mod;
tmp=(LL)tmp*quick_exp(fac[m-n],mod-2)%mod;
return tmp;
}
int n,m;
void init()
{
fac[0]=1;
for(int i=1;i<=N;i++) fac[i]=(LL)fac[i-1]*i%mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("rapid.in","r",stdin);
freopen("rapid.out","w",stdout);
#endif
init();
while(~scanf("%d%d",&n,&m))
{
if(n==1||m==1)
{
if(n==1&&m==1) printf("1\n");
else printf("0\n");
continue;
}
int ans = C(m+n-4,m-2);
printf("%d\n",ans);
}
return 0;
}