第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
输出走法的数量。
2 3
3
第一种做法是用dp,dp【i】【j】=dp[i-1][j]+dp[i][j-1]
需要注意的是dp[1][1-m] 和dp[1-n][1] 全部都设为1,因为走到那些点都只有一个走法能到达!!!!!
、之后从i=2开始枚举,这个点十分重要
第二种做法是组合数+逆原。
我们需要走n-m-2步,我们要从n-m-2步中挑选n-1步走横线。所以就是求C(n-m-2,n-1),不过需要注意的是,我们在组合数过程中肯定要用的除法,但是
我们不能用除法做,所以需要用到逆原,转变成乘法
法一:
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
int const mod=1000000000+7;
LL dp[1005][1005];
int main()
{
int n,m;
scanf("%d %d",&m,&n);
for(int i=1;i<=n;i++)
{
dp[1][i]=1;
}
for(int i=1;i<=m;i++){
dp[i][1]=1;
}
for(int i=2;i<=m;i++){
for(int j=2;j<=n;j++){
dp[i][j]=dp[i][j-1]%mod+dp[i-1][j]%mod;
}
}
//printf("%I64d\n",dp[127][17]%mod);
int res=dp[m][n]%mod;
printf("%d\n",res);
return 0;
}
法二:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
ll extend_gcd(ll a,ll b,ll &x,ll &y)
{
if(a==0&&b==0) return -1;//无最大公约数
if(b==0){x=1;y=0;return a;}
ll d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
ll mod_reverse(ll a,ll n)
{
ll x,y;
ll d=extend_gcd(a,n,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
ll c(ll m,ll n)
{
ll i,j,t1,t2,ans;
t1=t2=1;
for(i=n;i>=n-m+1;i--) t1=t1*i%mod;
for(i=1;i<=m;i++) t2=t2*i%mod;
return t1*mod_reverse(t2,mod)%mod;
}
int main()
{
ll n,m,ans;
cin>>m>>n;
ans=c(min(m-1,n-1),m+n-2);
cout<<ans<<endl;
return 0;
}