[hdu5698]: 瞬間移動(兩種方法求組合數)
阿新 • • 發佈:2019-01-25
瞬間移動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 4 5 Sample Output 10 Source Recommend wange2014 |
題解
自己畫出前面幾行幾列 找個規律出來
類似這個樣子
0 0000
01111
01234
013610
0141020
此時把這個矩陣斜著看 發現好像楊輝三角的規律
在仔細一想 第n行m列 就等於C(n+m-4,n-2) 或者C(n+m-4,m-2)相等的
於是求出這個組合數就可以了啊
今天學了求這個組合數(乘法逆元)的兩種方法:
1.擴充套件歐幾里得求乘法逆元
2.費馬小定理+快速冪
程式碼如下:
1.根據二項式定理直接算C 除的時候不用除直接乘上逆元即可
2.費馬小定理+快速冪#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; }
用快速冪+費馬小定理求組合數
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; }