1. 程式人生 > >HDU 5698 瞬間移動 [數論] [逆元] [組合數取模]

HDU 5698 瞬間移動 [數論] [逆元] [組合數取模]

瞬間移動
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 893 Accepted Submission(s): 476

Problem Description
有一個無限大的矩形,初始時你在左上角(即第一行第一列),每次你都可以選擇一個右下方格子,並瞬移過去(如從下圖中的紅色格子能直接瞬移到藍色格子),求到第n行第m列的格子有幾種方案,答案對1000000007取模。
這裡寫圖片描述
Input
多組測試資料。

兩個整數n,m(2≤n,m≤100000)

Output
一個整數表示答案

Sample Input
4 5

Sample Output
10

Source
2016”百度之星” - 初賽(Astar Round2B)

首先找出是一個楊輝三角。。。
那麼很容易得到 ans = C (m+n-4,m-2)
然後的話組合數取模,但是mod太大,這時候有三種方法:

  • 預處理階乘,然後直接定義法求解
  • 預處理N以內的逆元,然後用組合數線性遞推公式邊走邊求
  • 直接求出階乘,然後用遞迴求逆元,此時的數可能超過N

下面給出第一種方法,注意階乘要預處理到2N,因為是m+n-4數量級的。。。

#include<iostream>
#include<cstdio>
#include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm>
#ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) typedef long long LL; const int INF=0x3f3f3f3f; const int mod = 1000000007; const int maxn = 200005; const int N = 200000; int fac[maxn]; int quick_exp(int a,int p) { if(!p) return 1; if(p==1) return a%mod; int tmp=quick_exp(a,p>>1); tmp=(LL)tmp*tmp%mod; if(p&1) return (LL)tmp*a%mod; else return tmp; } int C(int m,int n) { int tmp=(LL)fac[m]*quick_exp(fac[n],mod-2)%mod; tmp=(LL)tmp*quick_exp(fac[m-n],mod-2)%mod; return tmp; } int n,m; void init() { fac[0]=1; for(int i=1;i<=N;i++) fac[i]=(LL)fac[i-1]*i%mod; } int main() { #ifndef ONLINE_JUDGE freopen("rapid.in","r",stdin); freopen("rapid.out","w",stdout); #endif init(); while(~scanf("%d%d",&n,&m)) { if(n==1||m==1) { if(n==1&&m==1) printf("1\n"); else printf("0\n"); continue; } int ans = C(m+n-4,m-2); printf("%d\n",ans); } return 0; }