LightOj 1170 - Counting Perfect BST (折半枚举 + 卡特兰树)
题目链接:
http://www.lightoj.com/volume_showproblem.php?problem=1170
题目描述:
给出一些满足完美性质的一列数(x > 1 and y > 1 such that m = xy.) 然后给出一个区间,问在这个区间中的完美数组成的搜索二叉树的个数是多少?
解题思路:
1,打标算出所有的完美数列中的数字
2,打表算出卡特兰数列,等着以后用
3,卡特兰数列递推式:F[N] = F[N-1] * ( 4 * N - 2 ) / ( N + 1 ), 求余的时候牵涉到逆元,用扩展欧几里德或者费马小定理求解逆元
准备到这里就万事大吉了!
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 8 #define LL long long 9 #define maxn 110100 10 #define mod 100000007 11 const LL Max = 1e10; 12 LL a[maxn], ans[maxn], num; 13 14 LL Extended_Euclid (LL a, LL b, LL &x, LL &y) 15 { 16 //处理 a * b > 0 的情况 17 if (b == 0) 18 { 19 x = 1; 20 y = 0; 21 return a; 22 } 23 24 LL r = Extended_Euclid (b, a%b, x, y), t; 25 t = x; 26 x = y; 27 y = t - a / b * y; 28 return r; 29 } 30 31 void init () 32 { 33 //memset (vis, 0, sizeof(vis)); 34 num = 0; 35 for (LL i=2; i<maxn; i++) 36 { 37 LL j = i * i; 38 while (j <= Max) 39 { 40 a[num ++] = j; 41 j *= i; 42 } 43 } 44 45 sort (a, a+ num); 46 num = unique (a, a+num) - a; 47 48 ans[0] = 0; 49 ans[1] = 1; 50 for (LL i=2; i<maxn; i++) 51 { 52 /// F[N] = F[N-1] * ( 4 * N - 2 ) / ( N + 1 ) 53 LL x, y, r; 54 r = Extended_Euclid (i+1, mod, x, y); 55 ans[i] = ans[i-1] * (4 * i - 2) % mod * (x % mod + mod ) % mod; 56 } 57 } 58 59 int main () 60 { 61 init (); 62 63 int T, L = 1; 64 cin >> T; 65 while (T --) 66 { 67 LL x, y; 68 scanf ("%lld %lld", &x, &y); 69 x = lower_bound (a, a+num, x) - a; 70 y = upper_bound (a, a+num, y) - a; 71 72 printf ("Case %d: %lld\n", L++, ans[y - x]); 73 } 74 return 0; 75 }
本文为博主原创文章,未经博主允许不得转载。