瞬间移动
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K
Total Submission(s): 1947 Accepted Submission(s): 886
Problem Description
有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n行第m列的格子有几种方案,答案对1000000007取模。
Input
多组测试数据。
两个整数n,m(2≤n,m≤100000)
Output
一个整数表示答案
Sample Input
4
Sample Output
10
解析:
枚举走的步数,假如为x。那么,对于行,要从1通过x步走到n。对于列,要从1通过x步走到m。这两个操作是独立的,所以可以乘起来。考虑行,那么问题就变成了,求从1到n通过x步的方案数,就相当于要把n 分为x 份,每份不能 为空的方案数。也就是一个经典的排列组合问题了,用插板法思想解决。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#define LL long long
using namespace std;
const int Max=100010;
const int mod=1000000007;
int n,m,ans;
int inv[Max],mul[Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline int ksm(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
inline void pre()
{
mul[0]=mul[1]=1;
for(int i=2;i<=100000;i++) mul[i]=((LL)mul[i-1]*(LL)i)%mod;
inv[1]=1;
for(int i=2;i<=100000;i++) inv[i]=ksm(mul[i],mod-2);
}
inline int C(int n,int m)
{
if(m==n || !m) return 1;
return ((LL)mul[n]*(LL)inv[m]%mod*(LL)inv[n-m]%mod)%mod;
}
int main()
{
pre();
while(~scanf("%d%d",&n,&m))
{
ans=0;
for(int i=1;i<=min(n,m);i++)
{
int sum1=C(n-2,i-1),sum2=C(m-2,i-1);
ans=((LL)ans+(LL)sum1*sum2%mod)%mod;
}
cout<<ans<<"\n";
}
return 0;
}