|
瞬间移动Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1178 Accepted Submission(s): 583
Problem Description
有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第
n
行第
m
列的格子有几种方案,答案对
1000000007
取模。
![]()
Input
多组测试数据。
两个整数 n,m(2≤n,m≤100000)
Output
一个整数表示答案
Sample Input
Sample Output
Source
Recommend
wange2014
|
题解
自己画出前面几行几列 找个规律出来
类似这个样子
0 0 0 0 0
0 1 1 1 1
0 1 2 3 4
0 1 3 6 10
0 1 4 10 20
此时把这个矩阵斜着看 发现好像杨辉三角的规律
在仔细一想 第n行m列 就等于C(n+m-4,n-2) 或者C(n+m-4,m-2)相等的
于是求出这个组合数就可以了啊
今天学了求这个组合数(乘法逆元)的两种方法:
1.扩展欧几里得求乘法逆元
2.费马小定理+快速幂
代码如下:
1.根据二项式定理直接算C 除的时候不用除直接乘上逆元即可
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mod 1000000007
#define ll long long
using namespace std;
int x,y;
void exgcd(int a,int b){
if(b==0) {x=1;y=0;}
else {
exgcd(b,a%b);
int t=x;
x=y;
y=t-(a/b)*y;
}
}
//求C(n+m-4,n-2) 二项式定理
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
ll ans=1;
for(int i=1;i<=n+m-4;i++)
ans=ans*i%mod;
for(int i=1;i<=n-2;i++){
exgcd(i,mod);
x=(x%mod+mod)%mod;//求逆元
ans=(ans*x)%mod;//乘上逆元
}
for(int i=1;i<=m-2;i++){//n+m+4-(n-2)=m-2
exgcd(i,mod);
x=(x%mod+mod)%mod;
ans=(ans*x)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
2.费马小定理+快速幂
用快速幂+费马小定理求组合数
1).扩展欧几里德:b*x+p*y=1 有解,x就是所求
2).费马小定理:b^(p-1)=1(mod p),故 b*b^(p-2)=1(mod p),所以x=b^(p-2)
这样的方法可以算出逆元的另一种求法为:x=b^(p-2)
前提是p是质数 否则费马小定理就不成立
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define mod 1000000007
using namespace std;
ll fac[200005];
void pre(){//预处理乘方
fac[1]=1;
for(int i=2;i<=200000;i++)
fac[i]=fac[i-1]*i%mod;
}
ll quick_pow(ll a,ll b){
ll ans=1;
for(ll i=b;i;i>>=1,a=(a*a)%mod)
if(i&1) ans=(ans*a)%mod;
return ans;
}
int main(){
pre();
int n,m;
// for(int i=1;i<=100;i++)
// printf("%d ",fac[i]);
while(scanf("%d%d",&n,&m)!=EOF){
ll ans;
ans=fac[n+m-4];
//printf("%lld\n",ans);
ans=ans*quick_pow(fac[n-2],mod-2)%mod;
//printf("%lld\n",quick_pow(fac[n-2],mod-2));
ans=ans*quick_pow(fac[m-2],mod-2)%mod;
printf("%lld\n",ans);
}
return 0;
}