Lightoj 1170 卡特兰数+扩展欧几里得算法

来源:互联网 发布:云智能网络 编辑:程序博客网 时间:2024/06/01 08:56

1.预处理先求出1e10范围内的所有完美的数

2.一个有n个值的二叉排序树的个数:

   先将这n个数排序,然后 可以选第1个数为根,那么就变成了  构造 0个节点的左子树 与 n-1个节点的右子树

                                                 选第2个数为根,那么就变成了  构造1个节点的左子树 与 n-2个节点的右子树

                                                  。。。。。

                                                 选第k个数为根,那么就变成了  构造 k-1个节点的左子树 与 n-1-k个节点的右子树

     那么 F[N] = F[0]*F[N-1] + F[1] * F[N-2] + ......+ F[K] * F[N-1-K] + ......+ F[N-1] * F[0];

  这个公式为卡特兰数的公式:

由此可得递推公式为  F[N] = F[N-1] * ( 4 * N - 2 ) / ( N + 1 )

3,由于该公式有 (N+1)^-1  那么对MOD取余的时候要用扩展欧几里得算法

具体见代码,或百度

4.那么有了以上三步之后 只需用二分法求出 1到a有多少个完美数 1到b有多少个完美数  然后通过上面的F[N] 直接得出结果

 

代码如下:

#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <iostream>using namespace std;#define SIZE 110100const long long MAX = 1e10;#define MOD 100000007#define LL long longLL temp[SIZE], M[SIZE], ans[SIZE];LL tot = 0, k = 0;void EGCD( LL a, LL b, LL &x, LL &y ){if( b == 0 ){x = 1;y = 0;return;}EGCD( b, a % b, x, y );LL tp = x;x = y;y = tp - a / b * y;}void initial(){tot = 1;k = 1;for( LL i = 2; i < SIZE; i++ ){LL j =  i * i;while( j <= MAX ){temp[k++] = j;j *= i;}}sort( temp + 1, temp + k );for( LL i = 1; i <= k; i++ ){if( temp[i] != temp[i+1] ){M[tot++] = temp[i];}}ans[0] = 0;ans[1] = 1;for( LL i = 2; i < SIZE; i++ ){LL x, y;EGCD( i + 1, MOD, x, y );ans[i] = ans[i-1] * ( 4 * i - 2 ) % MOD * ( x % MOD + MOD ) % MOD;}}int main(){initial();int T, Case = 1;LL a, b;cin >> T;while( T-- ){cin >> a >> b;LL l = 1, r = tot, mid;while( l < r ){mid = ( l + r ) / 2;if( M[mid] >= a ){//每次都求刚好等于a或者大于它的r = mid;}else{l = mid + 1;}}a = r;l = 1, r = tot;while( l < r ){mid = ( l + r ) / 2;if( M[mid] > b ){//每次求得大于它的r = mid;}else{l = mid + 1;}}b = r;cout << "Case " << Case++ << ": " << ans[b-a] << endl;}return 0;}


 

0 0
原创粉丝点击