分析:打表以后就能发现时卡特兰数, 但是有除法取余。
f[i] = f[i-1]*(4*i - 2)/(i+1);
看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展gcd, 不是用逆元吗。。
网上还有别人的解释,没看懂,贴一下:
(a / b) % m = ( a % (m*b)) / b
笔者注:鉴于ACM题目特别喜欢M=1000000007,为质数:
当gcd(b,m) = 1, 有性质: (a/b)%m = (a*b^-1)%m, 其中b^-1是b模m的逆元.
求出b相对于m的逆元b^(-1),即b*(b^(-1)) = 1 (mod m)。有b*b^(-1) - km = 1,其中k是一整数. 用Extended Euclid算法可以求出`b^(-1)。然后计算a*b^(-1) mod m = ( (a%m) * (b^(-1)%m ) % m; 其值与(a/b) mod m相同
推导:a/b = x (mod m) --两边同乘一个数--> a = bx (mod m) ---x=b^-1a-> a = (b^-1) ba (mod m)
再利用b^-1*b = 1(mod m) . 所以可以得出 x = b^-1*a是成立的。
所以 (a/b) mod m 的解与 (a*b^-1)%m的解是一样的。 而后着可以利用模对乘法的线性性
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #define LL __int64 7 using namespace std; 8 const int mo = 1000000000 + 7; 9 const int maxn = 1000000 + 10; 10 LL f[maxn]; 11 12 LL exgcd(LL a,LL b,LL &x,LL &y) 13 { 14 if(b==0) 15 { 16 x=1; y=0; return a; 17 } 18 LL d = exgcd(b,a%b,x,y); 19 LL t=x; 20 x=y; 21 y=t-a/b*y; 22 return d; 23 } 24 void init() 25 { 26 int i; 27 LL x, y; 28 f[0] = f[1] = 1; 29 for(i = 2; i < maxn-5; i++) 30 { 31 f[i] = f[i-1]*(4*i-2)%mo; 32 exgcd(i+1, mo, x, y); 33 f[i] = (f[i]*((x+mo)%mo))%mo; 34 } 35 } 36 int main() 37 { 38 int t, n, ca = 1; 39 init(); 40 scanf("%d", &t); 41 while(t--) 42 { 43 scanf("%d", &n); 44 printf("Case #%d:\n", ca++); 45 printf("%I64d\n", f[n]); 46 } 47 return 0; 48 }
扩展gcd:
1 //扩展 GCD 2 //求x, y使得gcd(a, b) = a * x + b * y; 3 4 int extgcd(int a, int b, int & x, int & y) 5 { 6 if (b == 0) { x=1; y=0; return a; } 7 int d = extgcd(b, a % b, x, y); 8 int t = x; x = y; y = t - a / b * y; 9 return d; 10 }
2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd),布布扣,bubuko.com
2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)
原文:http://www.cnblogs.com/bfshm/p/3753160.html