[hdu5698]: 瞬间移动(两种方法求组合数)

来源:互联网 发布:推荐淘宝蓝莓苗卖家 编辑:程序博客网 时间:2024/06/08 00:57

welcome to my blog!!!

瞬间移动

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(2n,m100000)
 

Output
一个整数表示答案
 

Sample Input
4 5
 

Sample Output
10
 

Source
2016"百度之星" - 初赛(Astar Round2B)
 

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-2exgcd(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 1000000007using 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;}


阅读全文
2 0