一个Catalan数的题,打表对每个数都求一次逆元会T,于是问到了一种求阶乘逆元的打表新方法。 比如打一个1~n的阶乘的逆元的表,假如叫inv[n],可以先用费马小定理什么的求出inv[n],再用递推公式求出前面的项。
我们记数字 x 的逆元为f(x) (%MOD)。
因为 n! = (n-1)! * n
所以 f(n!) = f( (n-1)! * n) = f( (n-1)! ) * f(n)。
所以 f( (n-1)! ) = f(n!) * f( f(n) ) = f(n!) * n (逆元的逆元就是他自身)
这样子我们就可以用后项推出前面的项了。
题目是说,有一个人从0点开始走路,每次可以向前走或者向后走,每次可以走一步,但是所有的位置必须大于等于0,问走过2n步之后又回到0点有多少种方法。
其实,如果我们把向前走看做是进栈,向后走看做是出栈,方法数就是Catalan数。
所以我们只需要打一张表然后查表就好了。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <cctype> 15 #include <time.h> 16 17 using namespace std; 18 19 typedef __int64 ll; 20 21 const int INF = 1<<30; 22 const int MAXN = (int) 2e6+55; 23 const ll MOD = (ll) 1e9+7; 24 25 ll ans[MAXN]; 26 ll fac[MAXN]; 27 ll inv[MAXN]; 28 29 inline ll myPow(ll x, ll n) { 30 ll res = 1; 31 while (n>0) { 32 if (n&1) res = (res*x)%MOD; 33 x = (x*x)%MOD; 34 n >>= 1; 35 } 36 return res; 37 } 38 39 int main() { 40 #ifdef Phantom01 41 freopen("HNU12933.txt", "r", stdin); 42 #endif //Phantom01 43 44 fac[0] = 1; 45 for (int i = 1; i < MAXN; i++) fac[i] = (fac[i-1]*i)%MOD; 46 inv[MAXN-1] = myPow(fac[MAXN-1], MOD-2); 47 for (int i = MAXN-2; i > 0; i--) { 48 inv[i] = (inv[i+1]*(i+1))%MOD; 49 } 50 51 for (int i = 1; i < (MAXN>>1); i++) 52 ans[i] = (((fac[2*i]*inv[i+1])%MOD)*inv[i])%MOD; 53 54 int T; 55 scanf("%d", &T); 56 57 int n; 58 while (T--) { 59 scanf("%d", &n); 60 printf("%I64d\n", ans[n]); 61 } 62 63 return 0; 64 }
其中,这个是用来打阶乘逆元的:
1 //阶乘 2 fac[0] = 1; 3 for (int i = 1; i < MAXN; i++) fac[i] = (fac[i-1]*i)%MOD; 4 //逆元 5 inv[MAXN-1] = myPow(fac[MAXN-1], MOD-2); 6 for (int i = MAXN-2; i > 0; i--) { 7 inv[i] = (inv[i+1]*(i+1))%MOD; 8 }
时间: 2024-10-11 16:18:51