51Nod 机器人走方格 V3 —— 卡特兰数、Lucas定理
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1120
题解:
1.看到这种题,马上就想到了卡特兰数。但卡特兰数最快也要O(n)的时间复杂度去递推或者预处理,而n的范围是1e9,所以行不通。但发现Mod的值为10007,感觉突破口在里头,但没有头绪。
2.后来发现了Lucas定理:
C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p,p为素数
这个式子大大缩小了n的范围,因此就可以直接上卡特兰数的公式了:
h(n) = C(2n,n) - C(2n,n+1),n=0,1,2...
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 //const int MOD = 1e9+7; 17 const int MAXN = 1e6+10; 18 19 const int MOD = 10007; 20 int qpow(int x, int y) 21 { 22 int s = 1; 23 while(y) 24 { 25 if(y&1) s = (s*x)%MOD; 26 x = (x*x)%MOD; 27 y >>= 1; 28 } 29 return s; 30 } 31 32 int A[2*MOD+10], inv[2*MOD+10]; 33 int C(int n, int m) 34 { 35 if(n<m) return 0; 36 return (((A[n]*inv[n-m])%MOD)*inv[m])%MOD; 37 } 38 39 int lacus(int n, int m) 40 { 41 int s = 1; 42 while(n&&m) 43 { 44 s = (s*C(n%MOD,m%MOD))%MOD; 45 n /= MOD; 46 m /= MOD; 47 } 48 return s; 49 } 50 51 void init() 52 { 53 A[0] = inv[0] = 1; 54 for(int i = 1; i<=2*MOD; i++) 55 { 56 A[i] = (i*A[i-1])%MOD; 57 inv[i] = qpow(A[i],MOD-2); 58 } 59 } 60 61 int main() 62 { 63 init(); 64 int n; 65 while(scanf("%d",&n)!=EOF) 66 { 67 n--; 68 int ans = (lacus(2*n,n)-lacus(2*n,n+1)+MOD)%MOD; 69 ans = (ans*2)%MOD; 70 printf("%d\n", ans); 71 } 72 }