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 }

 

posted @ 2016-04-20 19:49  罗茜  阅读(369)  评论(0编辑  收藏  举报